uuid/external/
serde_support.rs

1// Copyright 2013-2014 The Rust Project Developers.
2// Copyright 2018 The Uuid Project Developers.
3//
4// See the COPYRIGHT file at the top-level directory of this distribution.
5//
6// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9// option. This file may not be copied, modified, or distributed
10// except according to those terms.
11
12use crate::{
13    error::*,
14    fmt::{Braced, Hyphenated, Simple, Urn},
15    std::fmt,
16    Uuid,
17};
18use serde::{
19    de::{self, Error as _},
20    Deserialize, Deserializer, Serialize, Serializer,
21};
22
23impl Serialize for Uuid {
24    fn serialize<S: Serializer>(
25        &self,
26        serializer: S,
27    ) -> Result<S::Ok, S::Error> {
28        if serializer.is_human_readable() {
29            serializer.serialize_str(
30                self.hyphenated().encode_lower(&mut Uuid::encode_buffer()),
31            )
32        } else {
33            serializer.serialize_bytes(self.as_bytes())
34        }
35    }
36}
37
38impl Serialize for Hyphenated {
39    fn serialize<S: Serializer>(
40        &self,
41        serializer: S,
42    ) -> Result<S::Ok, S::Error> {
43        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
44    }
45}
46
47impl Serialize for Simple {
48    fn serialize<S: Serializer>(
49        &self,
50        serializer: S,
51    ) -> Result<S::Ok, S::Error> {
52        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
53    }
54}
55
56impl Serialize for Urn {
57    fn serialize<S: Serializer>(
58        &self,
59        serializer: S,
60    ) -> Result<S::Ok, S::Error> {
61        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
62    }
63}
64
65impl Serialize for Braced {
66    fn serialize<S: Serializer>(
67        &self,
68        serializer: S,
69    ) -> Result<S::Ok, S::Error> {
70        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
71    }
72}
73
74impl<'de> Deserialize<'de> for Uuid {
75    fn deserialize<D: Deserializer<'de>>(
76        deserializer: D,
77    ) -> Result<Self, D::Error> {
78        fn de_error<E: de::Error>(e: Error) -> E {
79            E::custom(format_args!("UUID parsing failed: {}", e))
80        }
81
82        if deserializer.is_human_readable() {
83            struct UuidVisitor;
84
85            impl<'vi> de::Visitor<'vi> for UuidVisitor {
86                type Value = Uuid;
87
88                fn expecting(
89                    &self,
90                    formatter: &mut fmt::Formatter<'_>,
91                ) -> fmt::Result {
92                    write!(formatter, "a UUID string")
93                }
94
95                fn visit_str<E: de::Error>(
96                    self,
97                    value: &str,
98                ) -> Result<Uuid, E> {
99                    value.parse::<Uuid>().map_err(de_error)
100                }
101
102                fn visit_bytes<E: de::Error>(
103                    self,
104                    value: &[u8],
105                ) -> Result<Uuid, E> {
106                    Uuid::from_slice(value).map_err(de_error)
107                }
108
109                fn visit_seq<A>(self, mut seq: A) -> Result<Uuid, A::Error>
110                where
111                    A: de::SeqAccess<'vi>,
112                {
113                    #[rustfmt::skip]
114                    let bytes = [
115                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
116                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
117                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
118                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
119                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
120                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
121                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
122                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
123                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
124                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
125                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
126                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
127                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
128                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
129                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
130                        match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(16, &self)) },
131                    ];
132
133                    Ok(Uuid::from_bytes(bytes))
134                }
135            }
136
137            deserializer.deserialize_str(UuidVisitor)
138        } else {
139            struct UuidBytesVisitor;
140
141            impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
142                type Value = Uuid;
143
144                fn expecting(
145                    &self,
146                    formatter: &mut fmt::Formatter<'_>,
147                ) -> fmt::Result {
148                    write!(formatter, "bytes")
149                }
150
151                fn visit_bytes<E: de::Error>(
152                    self,
153                    value: &[u8],
154                ) -> Result<Uuid, E> {
155                    Uuid::from_slice(value).map_err(de_error)
156                }
157            }
158
159            deserializer.deserialize_bytes(UuidBytesVisitor)
160        }
161    }
162}
163
164pub mod compact {
165    //! Serialize a [`Uuid`] as a `[u8; 16]`.
166    //!
167    //! [`Uuid`]: ../../struct.Uuid.html
168
169    /// Serialize from a [`Uuid`] as a `[u8; 16]`
170    ///
171    /// [`Uuid`]: ../../struct.Uuid.html
172    pub fn serialize<S>(
173        u: &crate::Uuid,
174        serializer: S,
175    ) -> Result<S::Ok, S::Error>
176    where
177        S: serde::Serializer,
178    {
179        serde::Serialize::serialize(u.as_bytes(), serializer)
180    }
181
182    /// Deserialize a `[u8; 16]` as a [`Uuid`]
183    ///
184    /// [`Uuid`]: ../../struct.Uuid.html
185    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
186    where
187        D: serde::Deserializer<'de>,
188    {
189        let bytes: [u8; 16] = serde::Deserialize::deserialize(deserializer)?;
190
191        Ok(crate::Uuid::from_bytes(bytes))
192    }
193
194    #[cfg(test)]
195    mod tests {
196        use serde_derive::*;
197        use serde_test::{self, Configure};
198
199        #[test]
200        fn test_serialize_compact() {
201            #[derive(Serialize, Debug, Deserialize, PartialEq)]
202            struct UuidContainer {
203                #[serde(with = "crate::serde::compact")]
204                u: crate::Uuid,
205            }
206
207            let uuid_bytes = b"F9168C5E-CEB2-4F";
208            let container = UuidContainer {
209                u: crate::Uuid::from_slice(uuid_bytes).unwrap(),
210            };
211
212            // more complex because of the struct wrapping the actual UUID
213            // serialization
214            serde_test::assert_tokens(
215                &container.compact(),
216                &[
217                    serde_test::Token::Struct {
218                        name: "UuidContainer",
219                        len: 1,
220                    },
221                    serde_test::Token::Str("u"),
222                    serde_test::Token::Tuple { len: 16 },
223                    serde_test::Token::U8(uuid_bytes[0]),
224                    serde_test::Token::U8(uuid_bytes[1]),
225                    serde_test::Token::U8(uuid_bytes[2]),
226                    serde_test::Token::U8(uuid_bytes[3]),
227                    serde_test::Token::U8(uuid_bytes[4]),
228                    serde_test::Token::U8(uuid_bytes[5]),
229                    serde_test::Token::U8(uuid_bytes[6]),
230                    serde_test::Token::U8(uuid_bytes[7]),
231                    serde_test::Token::U8(uuid_bytes[8]),
232                    serde_test::Token::U8(uuid_bytes[9]),
233                    serde_test::Token::U8(uuid_bytes[10]),
234                    serde_test::Token::U8(uuid_bytes[11]),
235                    serde_test::Token::U8(uuid_bytes[12]),
236                    serde_test::Token::U8(uuid_bytes[13]),
237                    serde_test::Token::U8(uuid_bytes[14]),
238                    serde_test::Token::U8(uuid_bytes[15]),
239                    serde_test::Token::TupleEnd,
240                    serde_test::Token::StructEnd,
241                ],
242            )
243        }
244    }
245}
246
247#[cfg(test)]
248mod serde_tests {
249    use super::*;
250
251    use serde_test::{Compact, Configure, Readable, Token};
252
253    #[test]
254    fn test_serialize_readable_string() {
255        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
256        let u = Uuid::parse_str(uuid_str).unwrap();
257        serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]);
258    }
259
260    #[test]
261    fn test_deserialize_readable_compact() {
262        let uuid_bytes = b"F9168C5E-CEB2-4F";
263        let u = Uuid::from_slice(uuid_bytes).unwrap();
264
265        serde_test::assert_de_tokens(
266            &u.readable(),
267            &[
268                serde_test::Token::Tuple { len: 16 },
269                serde_test::Token::U8(uuid_bytes[0]),
270                serde_test::Token::U8(uuid_bytes[1]),
271                serde_test::Token::U8(uuid_bytes[2]),
272                serde_test::Token::U8(uuid_bytes[3]),
273                serde_test::Token::U8(uuid_bytes[4]),
274                serde_test::Token::U8(uuid_bytes[5]),
275                serde_test::Token::U8(uuid_bytes[6]),
276                serde_test::Token::U8(uuid_bytes[7]),
277                serde_test::Token::U8(uuid_bytes[8]),
278                serde_test::Token::U8(uuid_bytes[9]),
279                serde_test::Token::U8(uuid_bytes[10]),
280                serde_test::Token::U8(uuid_bytes[11]),
281                serde_test::Token::U8(uuid_bytes[12]),
282                serde_test::Token::U8(uuid_bytes[13]),
283                serde_test::Token::U8(uuid_bytes[14]),
284                serde_test::Token::U8(uuid_bytes[15]),
285                serde_test::Token::TupleEnd,
286            ],
287        );
288    }
289
290    #[test]
291    fn test_deserialize_readable_bytes() {
292        let uuid_bytes = b"F9168C5E-CEB2-4F";
293        let u = Uuid::from_slice(uuid_bytes).unwrap();
294
295        serde_test::assert_de_tokens(
296            &u.readable(),
297            &[serde_test::Token::Bytes(uuid_bytes)],
298        );
299    }
300
301    #[test]
302    fn test_serialize_hyphenated() {
303        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
304        let u = Uuid::parse_str(uuid_str).unwrap();
305        serde_test::assert_ser_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
306    }
307
308    #[test]
309    fn test_serialize_simple() {
310        let uuid_str = "f9168c5eceb24faab6bf329bf39fa1e4";
311        let u = Uuid::parse_str(uuid_str).unwrap();
312        serde_test::assert_ser_tokens(&u.simple(), &[Token::Str(uuid_str)]);
313    }
314
315    #[test]
316    fn test_serialize_urn() {
317        let uuid_str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
318        let u = Uuid::parse_str(uuid_str).unwrap();
319        serde_test::assert_ser_tokens(&u.urn(), &[Token::Str(uuid_str)]);
320    }
321
322    #[test]
323    fn test_serialize_braced() {
324        let uuid_str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
325        let u = Uuid::parse_str(uuid_str).unwrap();
326        serde_test::assert_ser_tokens(&u.braced(), &[Token::Str(uuid_str)]);
327    }
328
329    #[test]
330    fn test_serialize_non_human_readable() {
331        let uuid_bytes = b"F9168C5E-CEB2-4F";
332        let u = Uuid::from_slice(uuid_bytes).unwrap();
333        serde_test::assert_tokens(
334            &u.compact(),
335            &[serde_test::Token::Bytes(&[
336                70, 57, 49, 54, 56, 67, 53, 69, 45, 67, 69, 66, 50, 45, 52, 70,
337            ])],
338        );
339    }
340
341    #[test]
342    fn test_de_failure() {
343        serde_test::assert_de_tokens_error::<Readable<Uuid>>(
344            &[Token::Str("hello_world")],
345            "UUID parsing failed: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `h` at 1",
346        );
347
348        serde_test::assert_de_tokens_error::<Compact<Uuid>>(
349            &[Token::Bytes(b"hello_world")],
350            "UUID parsing failed: invalid length: expected 16 bytes, found 11",
351        );
352    }
353}