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}