palette/serde.rs
1//! Utilities for serializing and deserializing with `serde`.
2//!
3//! These modules and functions can be combined with `serde`'s [field
4//! attributes](https://serde.rs/field-attrs.html) to better control how to
5//! serialize and deserialize colors. See each item's examples for more details.
6
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9use crate::{
10 blend::{PreAlpha, Premultiply},
11 cast::{self, ArrayCast, UintCast},
12 stimulus::Stimulus,
13 Alpha,
14};
15
16pub(crate) use self::{alpha_deserializer::AlphaDeserializer, alpha_serializer::AlphaSerializer};
17
18mod alpha_deserializer;
19mod alpha_serializer;
20
21/// Combines [`serialize_as_array`] and [`deserialize_as_array`] as a module for `#[serde(with = "...")]`.
22///
23/// ```
24/// use serde::{Serialize, Deserialize};
25/// use palette::{Srgb, Srgba};
26///
27/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
28/// struct MyColors {
29/// #[serde(with = "palette::serde::as_array")]
30/// opaque: Srgb,
31/// #[serde(with = "palette::serde::as_array")]
32/// transparent: Srgba,
33/// }
34///
35/// let my_colors = MyColors {
36/// opaque: Srgb::new(0.6, 0.8, 0.3),
37/// transparent: Srgba::new(0.6, 0.8, 0.3, 0.5),
38/// };
39///
40/// let json = serde_json::to_string(&my_colors).unwrap();
41///
42/// assert_eq!(
43/// json,
44/// r#"{"opaque":[0.6,0.8,0.3],"transparent":[0.6,0.8,0.3,0.5]}"#
45/// );
46///
47/// assert_eq!(
48/// serde_json::from_str::<MyColors>(&json).unwrap(),
49/// my_colors
50/// );
51/// ```
52pub mod as_array {
53 pub use super::deserialize_as_array as deserialize;
54 pub use super::serialize_as_array as serialize;
55}
56
57/// Serialize the value as an array of its components.
58///
59/// ```
60/// use serde::Serialize;
61/// use palette::{Srgb, Srgba};
62///
63/// #[derive(Serialize)]
64/// struct MyColors {
65/// #[serde(serialize_with = "palette::serde::serialize_as_array")]
66/// opaque: Srgb,
67/// #[serde(serialize_with = "palette::serde::serialize_as_array")]
68/// transparent: Srgba,
69/// }
70///
71/// let my_colors = MyColors {
72/// opaque: Srgb::new(0.6, 0.8, 0.3),
73/// transparent: Srgba::new(0.6, 0.8, 0.3, 0.5),
74/// };
75///
76/// assert_eq!(
77/// serde_json::to_string(&my_colors).unwrap(),
78/// r#"{"opaque":[0.6,0.8,0.3],"transparent":[0.6,0.8,0.3,0.5]}"#
79/// );
80/// ```
81pub fn serialize_as_array<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
82where
83 T: ArrayCast,
84 T::Array: Serialize,
85 S: Serializer,
86{
87 cast::into_array_ref(value).serialize(serializer)
88}
89
90/// Deserialize a value from an array of its components.
91///
92/// ```
93/// use serde::Deserialize;
94/// use palette::{Srgb, Srgba};
95///
96/// #[derive(Deserialize, PartialEq, Debug)]
97/// struct MyColors {
98/// #[serde(deserialize_with = "palette::serde::deserialize_as_array")]
99/// opaque: Srgb,
100/// #[serde(deserialize_with = "palette::serde::deserialize_as_array")]
101/// transparent: Srgba,
102/// }
103///
104/// let my_colors = MyColors {
105/// opaque: Srgb::new(0.6, 0.8, 0.3),
106/// transparent: Srgba::new(0.6, 0.8, 0.3, 0.5),
107/// };
108///
109/// let json = r#"{"opaque":[0.6,0.8,0.3],"transparent":[0.6,0.8,0.3,0.5]}"#;
110/// assert_eq!(
111/// serde_json::from_str::<MyColors>(json).unwrap(),
112/// my_colors
113/// );
114/// ```
115pub fn deserialize_as_array<'de, T, D>(deserializer: D) -> Result<T, D::Error>
116where
117 T: ArrayCast,
118 T::Array: Deserialize<'de>,
119 D: Deserializer<'de>,
120{
121 Ok(cast::from_array(T::Array::deserialize(deserializer)?))
122}
123
124/// Combines [`serialize_as_uint`] and [`deserialize_as_uint`] as a module for `#[serde(with = "...")]`.
125///
126/// ```
127/// use serde::{Serialize, Deserialize};
128/// use palette::{Srgb, Srgba, rgb::{PackedArgb, PackedRgba}};
129///
130/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
131/// struct MyColors {
132/// #[serde(with = "palette::serde::as_uint")]
133/// argb: PackedArgb,
134/// #[serde(with = "palette::serde::as_uint")]
135/// rgba: PackedRgba,
136/// }
137///
138/// let my_colors = MyColors {
139/// argb: Srgb::new(0x17, 0xC6, 0x4C).into(),
140/// rgba: Srgba::new(0x17, 0xC6, 0x4C, 0xFF).into(),
141/// };
142///
143/// let json = serde_json::to_string(&my_colors).unwrap();
144///
145/// assert_eq!(
146/// json,
147/// r#"{"argb":4279748172,"rgba":398871807}"#
148/// );
149///
150/// assert_eq!(
151/// serde_json::from_str::<MyColors>(&json).unwrap(),
152/// my_colors
153/// );
154/// ```
155pub mod as_uint {
156 pub use super::deserialize_as_uint as deserialize;
157 pub use super::serialize_as_uint as serialize;
158}
159
160/// Serialize the value as an unsigned integer.
161///
162/// ```
163/// use serde::Serialize;
164/// use palette::{Srgb, Srgba, rgb::{PackedArgb, PackedRgba}};
165///
166/// #[derive(Serialize)]
167/// struct MyColors {
168/// #[serde(serialize_with = "palette::serde::serialize_as_uint")]
169/// argb: PackedArgb,
170/// #[serde(serialize_with = "palette::serde::serialize_as_uint")]
171/// rgba: PackedRgba,
172/// }
173///
174/// let my_colors = MyColors {
175/// argb: Srgb::new(0x17, 0xC6, 0x4C).into(),
176/// rgba: Srgba::new(0x17, 0xC6, 0x4C, 0xFF).into(),
177/// };
178///
179/// assert_eq!(
180/// serde_json::to_string(&my_colors).unwrap(),
181/// r#"{"argb":4279748172,"rgba":398871807}"#
182/// );
183/// ```
184pub fn serialize_as_uint<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
185where
186 T: UintCast,
187 T::Uint: Serialize,
188 S: Serializer,
189{
190 cast::into_uint_ref(value).serialize(serializer)
191}
192
193/// Deserialize a value from an unsigned integer.
194///
195/// ```
196/// use serde::Deserialize;
197/// use palette::{Srgb, Srgba, rgb::{PackedArgb, PackedRgba}};
198///
199/// #[derive(Deserialize, PartialEq, Debug)]
200/// struct MyColors {
201/// #[serde(deserialize_with = "palette::serde::deserialize_as_uint")]
202/// argb: PackedArgb,
203/// #[serde(deserialize_with = "palette::serde::deserialize_as_uint")]
204/// rgba: PackedRgba,
205/// }
206///
207/// let my_colors = MyColors {
208/// argb: Srgb::new(0x17, 0xC6, 0x4C).into(),
209/// rgba: Srgba::new(0x17, 0xC6, 0x4C, 0xFF).into(),
210/// };
211///
212/// let json = r#"{"argb":4279748172,"rgba":398871807}"#;
213/// assert_eq!(
214/// serde_json::from_str::<MyColors>(json).unwrap(),
215/// my_colors
216/// );
217/// ```
218pub fn deserialize_as_uint<'de, T, D>(deserializer: D) -> Result<T, D::Error>
219where
220 T: UintCast,
221 T::Uint: Deserialize<'de>,
222 D: Deserializer<'de>,
223{
224 Ok(cast::from_uint(T::Uint::deserialize(deserializer)?))
225}
226
227/// Deserialize a transparent color without requiring the alpha to be specified.
228///
229/// A color with missing alpha will be interpreted as fully opaque.
230///
231/// ```
232/// use serde::Deserialize;
233/// use palette::Srgba;
234///
235/// #[derive(Deserialize, PartialEq, Debug)]
236/// struct MyColors {
237/// #[serde(deserialize_with = "palette::serde::deserialize_with_optional_alpha")]
238/// opaque: Srgba,
239/// #[serde(deserialize_with = "palette::serde::deserialize_with_optional_alpha")]
240/// transparent: Srgba,
241/// }
242///
243/// let my_colors = MyColors {
244/// opaque: Srgba::new(0.6, 0.8, 0.3, 1.0),
245/// transparent: Srgba::new(0.6, 0.8, 0.3, 0.5),
246/// };
247///
248/// let json = r#"{
249/// "opaque":{"red":0.6,"green":0.8,"blue":0.3},
250/// "transparent":{"red":0.6,"green":0.8,"blue":0.3,"alpha":0.5}
251/// }"#;
252/// assert_eq!(
253/// serde_json::from_str::<MyColors>(json).unwrap(),
254/// my_colors
255/// );
256/// ```
257pub fn deserialize_with_optional_alpha<'de, T, A, D>(
258 deserializer: D,
259) -> Result<Alpha<T, A>, D::Error>
260where
261 T: Deserialize<'de>,
262 A: Stimulus + Deserialize<'de>,
263 D: Deserializer<'de>,
264{
265 let mut alpha: Option<A> = None;
266
267 let color = T::deserialize(crate::serde::AlphaDeserializer {
268 inner: deserializer,
269 alpha: &mut alpha,
270 })?;
271
272 Ok(Alpha {
273 color,
274 alpha: alpha.unwrap_or_else(A::max_intensity),
275 })
276}
277
278/// Deserialize a premultiplied transparent color without requiring the alpha to be specified.
279///
280/// A color with missing alpha will be interpreted as fully opaque.
281///
282/// ```
283/// use serde::Deserialize;
284/// use palette::{LinSrgba, LinSrgb, blend::PreAlpha};
285///
286/// type PreRgba = PreAlpha<LinSrgb<f32>>;
287///
288/// #[derive(Deserialize, PartialEq, Debug)]
289/// struct MyColors {
290/// #[serde(deserialize_with = "palette::serde::deserialize_with_optional_pre_alpha")]
291/// opaque: PreRgba,
292/// #[serde(deserialize_with = "palette::serde::deserialize_with_optional_pre_alpha")]
293/// transparent: PreRgba,
294/// }
295///
296/// let my_colors = MyColors {
297/// opaque: LinSrgba::new(0.6, 0.8, 0.3, 1.0).into(),
298/// transparent: LinSrgba::new(0.6, 0.8, 0.3, 0.5).into(),
299/// };
300///
301/// let json = r#"{
302/// "opaque":{"red":0.6,"green":0.8,"blue":0.3},
303/// "transparent":{"red":0.3,"green":0.4,"blue":0.15,"alpha":0.5}
304/// }"#;
305/// assert_eq!(
306/// serde_json::from_str::<MyColors>(json).unwrap(),
307/// my_colors
308/// );
309/// ```
310pub fn deserialize_with_optional_pre_alpha<'de, T, D>(
311 deserializer: D,
312) -> Result<PreAlpha<T>, D::Error>
313where
314 T: Premultiply + Deserialize<'de>,
315 T::Scalar: Stimulus + Deserialize<'de>,
316 D: Deserializer<'de>,
317{
318 let mut alpha: Option<T::Scalar> = None;
319
320 let color = T::deserialize(crate::serde::AlphaDeserializer {
321 inner: deserializer,
322 alpha: &mut alpha,
323 })?;
324
325 Ok(PreAlpha {
326 color,
327 alpha: alpha.unwrap_or_else(T::Scalar::max_intensity),
328 })
329}