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 core::marker::PhantomData;
13
14use crate::{
15    error::*,
16    fmt::{Braced, Hyphenated, Simple, Urn},
17    non_nil::NonNilUuid,
18    std::fmt,
19    Bytes, Uuid,
20};
21use serde_core::{
22    de::{self, Error as _},
23    Deserialize, Deserializer, Serialize, Serializer,
24};
25
26impl Serialize for Uuid {
27    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
28        if serializer.is_human_readable() {
29            serializer.serialize_str(self.hyphenated().encode_lower(&mut Uuid::encode_buffer()))
30        } else {
31            serializer.serialize_bytes(self.as_bytes())
32        }
33    }
34}
35
36impl Serialize for NonNilUuid {
37    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38    where
39        S: serde_core::Serializer,
40    {
41        Uuid::from(*self).serialize(serializer)
42    }
43}
44
45impl Serialize for Hyphenated {
46    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
47        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
48    }
49}
50
51impl Serialize for Simple {
52    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
53        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
54    }
55}
56
57impl Serialize for Urn {
58    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
59        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
60    }
61}
62
63impl Serialize for Braced {
64    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
65        serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
66    }
67}
68
69struct UuidReadableVisitor<T> {
70    expecting: &'static str,
71    _marker: PhantomData<T>,
72}
73
74impl<'vi, T: UuidDeserialize> de::Visitor<'vi> for UuidReadableVisitor<T> {
75    type Value = T;
76
77    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
78        formatter.write_str(self.expecting)
79    }
80
81    fn visit_str<E: de::Error>(self, value: &str) -> Result<T, E> {
82        T::from_str(value).map_err(de_error)
83    }
84
85    fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<T, E> {
86        T::from_slice(value).map_err(de_error)
87    }
88
89    fn visit_seq<A>(self, mut seq: A) -> Result<T, A::Error>
90    where
91        A: de::SeqAccess<'vi>,
92    {
93        #[rustfmt::skip]
94        let bytes = [
95            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(0, &self)) },
96            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(1, &self)) },
97            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(2, &self)) },
98            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(3, &self)) },
99            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(4, &self)) },
100            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(5, &self)) },
101            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(6, &self)) },
102            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(7, &self)) },
103            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(8, &self)) },
104            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(9, &self)) },
105            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(10, &self)) },
106            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(11, &self)) },
107            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(12, &self)) },
108            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(13, &self)) },
109            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(14, &self)) },
110            match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(15, &self)) },
111        ];
112
113        T::from_bytes(bytes).map_err(de_error)
114    }
115}
116
117struct UuidBytesVisitor<T> {
118    _marker: PhantomData<T>,
119}
120
121impl<'vi, T: UuidDeserialize> de::Visitor<'vi> for UuidBytesVisitor<T> {
122    type Value = T;
123
124    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
125        write!(formatter, "a 16 byte array")
126    }
127
128    fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<T, E> {
129        T::from_slice(value).map_err(de_error)
130    }
131}
132
133fn de_error<E: de::Error>(e: Error) -> E {
134    E::custom(format_args!("UUID parsing failed: {}", e))
135}
136
137trait UuidDeserialize {
138    fn from_str(formatted: &str) -> Result<Self, Error>
139    where
140        Self: Sized;
141    fn from_slice(bytes: &[u8]) -> Result<Self, Error>
142    where
143        Self: Sized;
144    fn from_bytes(bytes: Bytes) -> Result<Self, Error>
145    where
146        Self: Sized;
147}
148
149impl UuidDeserialize for Uuid {
150    fn from_str(formatted: &str) -> Result<Self, Error> {
151        formatted.parse()
152    }
153
154    fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
155        Uuid::from_slice(bytes)
156    }
157
158    fn from_bytes(bytes: Bytes) -> Result<Self, Error> {
159        Ok(Uuid::from_bytes(bytes))
160    }
161}
162
163impl<'de> Deserialize<'de> for Uuid {
164    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
165        if deserializer.is_human_readable() {
166            deserializer.deserialize_str(UuidReadableVisitor {
167                expecting: "a formatted UUID string",
168                _marker: PhantomData::<Uuid>,
169            })
170        } else {
171            deserializer.deserialize_bytes(UuidBytesVisitor {
172                _marker: PhantomData::<Uuid>,
173            })
174        }
175    }
176}
177
178impl UuidDeserialize for Braced {
179    fn from_str(formatted: &str) -> Result<Self, Error> {
180        formatted.parse()
181    }
182
183    fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
184        Ok(Uuid::from_slice(bytes)?.into())
185    }
186
187    fn from_bytes(bytes: Bytes) -> Result<Self, Error> {
188        Ok(Uuid::from_bytes(bytes).into())
189    }
190}
191
192impl<'de> Deserialize<'de> for Braced {
193    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
194        deserializer.deserialize_str(UuidReadableVisitor {
195            expecting: "a UUID string in the braced format",
196            _marker: PhantomData::<Braced>,
197        })
198    }
199}
200
201impl UuidDeserialize for Hyphenated {
202    fn from_str(formatted: &str) -> Result<Self, Error> {
203        formatted.parse()
204    }
205
206    fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
207        Ok(Uuid::from_slice(bytes)?.into())
208    }
209
210    fn from_bytes(bytes: Bytes) -> Result<Self, Error> {
211        Ok(Uuid::from_bytes(bytes).into())
212    }
213}
214
215impl<'de> Deserialize<'de> for Hyphenated {
216    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
217        deserializer.deserialize_str(UuidReadableVisitor {
218            expecting: "a UUID string in the hyphenated format",
219            _marker: PhantomData::<Hyphenated>,
220        })
221    }
222}
223
224impl UuidDeserialize for Simple {
225    fn from_str(formatted: &str) -> Result<Self, Error> {
226        formatted.parse()
227    }
228
229    fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
230        Ok(Uuid::from_slice(bytes)?.into())
231    }
232
233    fn from_bytes(bytes: Bytes) -> Result<Self, Error> {
234        Ok(Uuid::from_bytes(bytes).into())
235    }
236}
237
238impl<'de> Deserialize<'de> for Simple {
239    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
240        deserializer.deserialize_str(UuidReadableVisitor {
241            expecting: "a UUID string in the simple format",
242            _marker: PhantomData::<Simple>,
243        })
244    }
245}
246
247impl UuidDeserialize for Urn {
248    fn from_str(formatted: &str) -> Result<Self, Error> {
249        formatted.parse()
250    }
251
252    fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
253        Ok(Uuid::from_slice(bytes)?.into())
254    }
255
256    fn from_bytes(bytes: Bytes) -> Result<Self, Error> {
257        Ok(Uuid::from_bytes(bytes).into())
258    }
259}
260
261impl<'de> Deserialize<'de> for Urn {
262    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
263        deserializer.deserialize_str(UuidReadableVisitor {
264            expecting: "a UUID string in the URN format",
265            _marker: PhantomData::<Urn>,
266        })
267    }
268}
269
270impl<'de> Deserialize<'de> for NonNilUuid {
271    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
272    where
273        D: serde_core::Deserializer<'de>,
274    {
275        let uuid = Uuid::deserialize(deserializer)?;
276
277        NonNilUuid::try_from(uuid).map_err(|_| {
278            de::Error::invalid_value(de::Unexpected::Other("nil UUID"), &"a non-nil UUID")
279        })
280    }
281}
282
283pub mod compact {
284    //! Serialize a [`Uuid`] as a `[u8; 16]`.
285    //!
286    //! [`Uuid`]: ../../struct.Uuid.html
287
288    /// Serialize from a [`Uuid`] as a `[u8; 16]`
289    ///
290    /// [`Uuid`]: ../../struct.Uuid.html
291    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
292    where
293        S: serde_core::Serializer,
294    {
295        serde_core::Serialize::serialize(u.as_bytes(), serializer)
296    }
297
298    /// Deserialize a `[u8; 16]` as a [`Uuid`]
299    ///
300    /// [`Uuid`]: ../../struct.Uuid.html
301    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
302    where
303        D: serde_core::Deserializer<'de>,
304    {
305        let bytes: [u8; 16] = serde_core::Deserialize::deserialize(deserializer)?;
306
307        Ok(crate::Uuid::from_bytes(bytes))
308    }
309
310    #[cfg(test)]
311    mod tests {
312        use serde_derive::*;
313        use serde_test::Configure;
314
315        #[test]
316        fn test_serialize_compact() {
317            #[derive(Serialize, Debug, Deserialize, PartialEq)]
318            struct UuidContainer {
319                #[serde(with = "crate::serde::compact")]
320                u: crate::Uuid,
321            }
322
323            let uuid_bytes = b"F9168C5E-CEB2-4F";
324            let container = UuidContainer {
325                u: crate::Uuid::from_slice(uuid_bytes).unwrap(),
326            };
327
328            // more complex because of the struct wrapping the actual UUID
329            // serialization
330            serde_test::assert_tokens(
331                &container.compact(),
332                &[
333                    serde_test::Token::Struct {
334                        name: "UuidContainer",
335                        len: 1,
336                    },
337                    serde_test::Token::Str("u"),
338                    serde_test::Token::Tuple { len: 16 },
339                    serde_test::Token::U8(uuid_bytes[0]),
340                    serde_test::Token::U8(uuid_bytes[1]),
341                    serde_test::Token::U8(uuid_bytes[2]),
342                    serde_test::Token::U8(uuid_bytes[3]),
343                    serde_test::Token::U8(uuid_bytes[4]),
344                    serde_test::Token::U8(uuid_bytes[5]),
345                    serde_test::Token::U8(uuid_bytes[6]),
346                    serde_test::Token::U8(uuid_bytes[7]),
347                    serde_test::Token::U8(uuid_bytes[8]),
348                    serde_test::Token::U8(uuid_bytes[9]),
349                    serde_test::Token::U8(uuid_bytes[10]),
350                    serde_test::Token::U8(uuid_bytes[11]),
351                    serde_test::Token::U8(uuid_bytes[12]),
352                    serde_test::Token::U8(uuid_bytes[13]),
353                    serde_test::Token::U8(uuid_bytes[14]),
354                    serde_test::Token::U8(uuid_bytes[15]),
355                    serde_test::Token::TupleEnd,
356                    serde_test::Token::StructEnd,
357                ],
358            )
359        }
360    }
361}
362
363/// Serialize from a [`Uuid`] as a `uuid::fmt::Simple`
364///
365/// [`Uuid`]: ../../struct.Uuid.html
366///
367/// ## Example
368///
369/// ```rust
370/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
371/// struct StructA {
372///     // This will change both serailization and deserialization
373///     #[serde(with = "uuid::serde::simple")]
374///     id: uuid::Uuid,
375/// }
376///
377/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
378/// struct StructB {
379///     // This will be serialized as uuid::fmt::Simple and deserialize from all valid formats
380///     #[serde(serialize_with = "uuid::serde::simple::serialize")]
381///     id: uuid::Uuid,
382/// }
383/// ```
384pub mod simple {
385    use super::*;
386
387    /// Serialize from a [`Uuid`] as a `uuid::fmt::Simple`
388    ///
389    /// [`Uuid`]: ../../struct.Uuid.html
390    ///
391    /// # Example
392    ///
393    /// ```rust
394    /// #[derive(serde_derive::Serialize)]
395    /// struct Struct {
396    ///     // This will be serialize as uuid::fmt::Simple
397    ///     #[serde(serialize_with = "uuid::serde::simple::serialize")]
398    ///     id: uuid::Uuid,
399    /// }
400    ///
401    /// ```
402    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
403    where
404        S: serde_core::Serializer,
405    {
406        serde_core::Serialize::serialize(u.as_simple(), serializer)
407    }
408
409    /// Deserialize a simple Uuid string as a [`Uuid`]
410    ///
411    /// [`Uuid`]: ../../struct.Uuid.html
412    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
413    where
414        D: serde_core::Deserializer<'de>,
415    {
416        Ok(Simple::deserialize(deserializer)?.into())
417    }
418
419    #[cfg(test)]
420    mod tests {
421        use serde::de::{self, Error};
422        use serde_test::{Readable, Token};
423
424        use super::*;
425
426        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
427        const SIMPLE_UUID_STR: &str = "f9168c5eceb24faab6bf329bf39fa1e4";
428
429        #[test]
430        fn test_serialize_as_simple() {
431            #[derive(serde_derive::Serialize)]
432            struct Struct(#[serde(with = "super")] crate::Uuid);
433
434            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
435            serde_test::assert_ser_tokens(
436                &u,
437                &[
438                    Token::NewtypeStruct { name: "Struct" },
439                    Token::Str(SIMPLE_UUID_STR),
440                ],
441            );
442        }
443
444        #[test]
445        fn test_de_from_simple() {
446            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
447            struct Struct(#[serde(with = "super")] crate::Uuid);
448            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
449            serde_test::assert_de_tokens::<Struct>(
450                &s,
451                &[
452                    Token::TupleStruct {
453                        name: "Struct",
454                        len: 1,
455                    },
456                    Token::BorrowedStr(SIMPLE_UUID_STR),
457                    Token::TupleStructEnd,
458                ],
459            );
460        }
461
462        #[test]
463        fn test_de_reject_hypenated() {
464            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
465            struct Struct(#[serde(with = "super")] crate::Uuid);
466            serde_test::assert_de_tokens_error::<Readable<Struct>>(
467                &[
468                    Token::TupleStruct {
469                        name: "Struct",
470                        len: 1,
471                    },
472                    Token::BorrowedStr(HYPHENATED_UUID_STR),
473                    Token::TupleStructEnd,
474                ],
475                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
476            );
477        }
478    }
479}
480
481/// Serialize from a [`Uuid`] as a `uuid::fmt::Braced`
482///
483/// [`Uuid`]: ../../struct.Uuid.html
484///
485/// ## Example
486///
487/// ```rust
488/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
489/// struct StructA {
490///     // This will change both serailization and deserialization
491///     #[serde(with = "uuid::serde::braced")]
492///     id: uuid::Uuid,
493/// }
494///
495/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
496/// struct StructB {
497///     // This will be serialized as uuid::fmt::Urn and deserialize from all valid formats
498///     #[serde(serialize_with = "uuid::serde::braced::serialize")]
499///     id: uuid::Uuid,
500/// }
501/// ```
502pub mod braced {
503    use super::*;
504
505    /// Serialize from a [`Uuid`] as a `uuid::fmt::Braced`
506    ///
507    /// [`Uuid`]: ../../struct.Uuid.html
508    ///
509    /// # Example
510    ///
511    /// ```rust
512    /// #[derive(serde_derive::Serialize)]
513    /// struct Struct {
514    ///     // This will be serialize as uuid::fmt::Braced
515    ///     #[serde(serialize_with = "uuid::serde::braced::serialize")]
516    ///     id: uuid::Uuid,
517    /// }
518    ///
519    /// ```
520    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
521    where
522        S: serde_core::Serializer,
523    {
524        serde_core::Serialize::serialize(u.as_braced(), serializer)
525    }
526
527    /// Deserialize a braced Uuid string as a [`Uuid`]
528    ///
529    /// [`Uuid`]: ../../struct.Uuid.html
530    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
531    where
532        D: serde_core::Deserializer<'de>,
533    {
534        Ok(Braced::deserialize(deserializer)?.into())
535    }
536
537    #[cfg(test)]
538    mod tests {
539
540        use serde::de::{self, Error};
541        use serde_test::{Readable, Token};
542
543        use super::*;
544
545        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
546        const BRACED_UUID_STR: &str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
547
548        #[test]
549        fn test_serialize_as_braced() {
550            #[derive(serde_derive::Serialize)]
551            struct Struct(#[serde(with = "super")] crate::Uuid);
552
553            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
554            serde_test::assert_ser_tokens(
555                &u,
556                &[
557                    Token::NewtypeStruct { name: "Struct" },
558                    Token::Str(BRACED_UUID_STR),
559                ],
560            );
561        }
562
563        #[test]
564        fn test_de_from_braced() {
565            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
566            struct Struct(#[serde(with = "super")] crate::Uuid);
567            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
568            serde_test::assert_de_tokens::<Struct>(
569                &s,
570                &[
571                    Token::TupleStruct {
572                        name: "Struct",
573                        len: 1,
574                    },
575                    Token::BorrowedStr(BRACED_UUID_STR),
576                    Token::TupleStructEnd,
577                ],
578            );
579        }
580
581        #[test]
582        fn test_de_reject_hypenated() {
583            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
584            struct Struct(#[serde(with = "super")] crate::Uuid);
585            serde_test::assert_de_tokens_error::<Readable<Struct>>(
586                &[
587                    Token::TupleStruct {
588                        name: "Struct",
589                        len: 1,
590                    },
591                    Token::BorrowedStr(HYPHENATED_UUID_STR),
592                    Token::TupleStructEnd,
593                ],
594                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
595            );
596        }
597    }
598}
599
600/// Serialize from a [`Uuid`] as a `uuid::fmt::Urn`
601///
602/// [`Uuid`]: ../../struct.Uuid.html
603///
604/// ## Example
605///
606/// ```rust
607/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
608/// struct StructA {
609///     // This will change both serailization and deserialization
610///     #[serde(with = "uuid::serde::urn")]
611///     id: uuid::Uuid,
612/// }
613///
614/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
615/// struct StructB {
616///     // This will be serialized as uuid::fmt::Urn and deserialize from all valid formats
617///     #[serde(serialize_with = "uuid::serde::urn::serialize")]
618///     id: uuid::Uuid,
619/// }
620/// ```
621pub mod urn {
622    use super::*;
623
624    /// Serialize from a [`Uuid`] as a `uuid::fmt::Urn`
625    ///
626    /// [`Uuid`]: ../../struct.Uuid.html
627    ///
628    /// # Example
629    ///
630    /// ```rust
631    /// #[derive(serde_derive::Serialize)]
632    /// struct Struct {
633    ///     // This will be serialize as uuid::fmt::Urn
634    ///     #[serde(serialize_with = "uuid::serde::urn::serialize")]
635    ///     id: uuid::Uuid,
636    /// }
637    ///
638    /// ```
639    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
640    where
641        S: serde_core::Serializer,
642    {
643        serde_core::Serialize::serialize(u.as_urn(), serializer)
644    }
645
646    /// Deserialize a urn Uuid string as a [`Uuid`]
647    ///
648    /// [`Uuid`]: ../../struct.Uuid.html
649    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
650    where
651        D: serde_core::Deserializer<'de>,
652    {
653        Ok(Urn::deserialize(deserializer)?.into())
654    }
655
656    #[cfg(test)]
657    mod tests {
658        use serde::de::{self, Error};
659        use serde_test::{Readable, Token};
660
661        use super::*;
662
663        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
664        const URN_UUID_STR: &str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
665
666        #[test]
667        fn test_serialize_as_urn() {
668            #[derive(serde_derive::Serialize)]
669            struct Struct(#[serde(with = "super")] crate::Uuid);
670
671            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
672            serde_test::assert_ser_tokens(
673                &u,
674                &[
675                    Token::NewtypeStruct { name: "Struct" },
676                    Token::Str(URN_UUID_STR),
677                ],
678            );
679        }
680
681        #[test]
682        fn test_de_from_urn() {
683            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
684            struct Struct(#[serde(with = "super")] crate::Uuid);
685            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
686            serde_test::assert_de_tokens::<Struct>(
687                &s,
688                &[
689                    Token::TupleStruct {
690                        name: "Struct",
691                        len: 1,
692                    },
693                    Token::BorrowedStr(URN_UUID_STR),
694                    Token::TupleStructEnd,
695                ],
696            );
697        }
698
699        #[test]
700        fn test_de_reject_hypenated() {
701            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
702            struct Struct(#[serde(with = "super")] crate::Uuid);
703            serde_test::assert_de_tokens_error::<Readable<Struct>>(
704                &[
705                    Token::TupleStruct {
706                        name: "Struct",
707                        len: 1,
708                    },
709                    Token::BorrowedStr(HYPHENATED_UUID_STR),
710                    Token::TupleStructEnd,
711                ],
712                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
713            );
714        }
715    }
716}
717
718#[cfg(test)]
719mod serde_tests {
720    use super::*;
721
722    use serde_test::{Compact, Configure, Readable, Token};
723
724    #[test]
725    fn test_serialize_readable_string() {
726        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
727        let u = Uuid::parse_str(uuid_str).unwrap();
728        serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]);
729    }
730
731    #[test]
732    fn test_deserialize_readable_compact() {
733        let uuid_bytes = b"F9168C5E-CEB2-4F";
734        let u = Uuid::from_slice(uuid_bytes).unwrap();
735
736        serde_test::assert_de_tokens(
737            &u.readable(),
738            &[
739                serde_test::Token::Tuple { len: 16 },
740                serde_test::Token::U8(uuid_bytes[0]),
741                serde_test::Token::U8(uuid_bytes[1]),
742                serde_test::Token::U8(uuid_bytes[2]),
743                serde_test::Token::U8(uuid_bytes[3]),
744                serde_test::Token::U8(uuid_bytes[4]),
745                serde_test::Token::U8(uuid_bytes[5]),
746                serde_test::Token::U8(uuid_bytes[6]),
747                serde_test::Token::U8(uuid_bytes[7]),
748                serde_test::Token::U8(uuid_bytes[8]),
749                serde_test::Token::U8(uuid_bytes[9]),
750                serde_test::Token::U8(uuid_bytes[10]),
751                serde_test::Token::U8(uuid_bytes[11]),
752                serde_test::Token::U8(uuid_bytes[12]),
753                serde_test::Token::U8(uuid_bytes[13]),
754                serde_test::Token::U8(uuid_bytes[14]),
755                serde_test::Token::U8(uuid_bytes[15]),
756                serde_test::Token::TupleEnd,
757            ],
758        );
759    }
760
761    #[test]
762    fn test_deserialize_readable_bytes() {
763        let uuid_bytes = b"F9168C5E-CEB2-4F";
764        let u = Uuid::from_slice(uuid_bytes).unwrap();
765
766        serde_test::assert_de_tokens(&u.readable(), &[serde_test::Token::Bytes(uuid_bytes)]);
767    }
768
769    #[test]
770    fn test_serialize_hyphenated() {
771        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
772        let u = Uuid::parse_str(uuid_str).unwrap();
773        serde_test::assert_ser_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
774        serde_test::assert_de_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
775    }
776
777    #[test]
778    fn test_serialize_simple() {
779        let uuid_str = "f9168c5eceb24faab6bf329bf39fa1e4";
780        let u = Uuid::parse_str(uuid_str).unwrap();
781        serde_test::assert_ser_tokens(&u.simple(), &[Token::Str(uuid_str)]);
782        serde_test::assert_de_tokens(&u.simple(), &[Token::Str(uuid_str)]);
783    }
784
785    #[test]
786    fn test_serialize_urn() {
787        let uuid_str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
788        let u = Uuid::parse_str(uuid_str).unwrap();
789        serde_test::assert_ser_tokens(&u.urn(), &[Token::Str(uuid_str)]);
790        serde_test::assert_de_tokens(&u.urn(), &[Token::Str(uuid_str)]);
791    }
792
793    #[test]
794    fn test_serialize_braced() {
795        let uuid_str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
796        let u = Uuid::parse_str(uuid_str).unwrap();
797        serde_test::assert_ser_tokens(&u.braced(), &[Token::Str(uuid_str)]);
798        serde_test::assert_de_tokens(&u.braced(), &[Token::Str(uuid_str)]);
799    }
800
801    #[test]
802    fn test_serialize_non_human_readable() {
803        let uuid_bytes = b"F9168C5E-CEB2-4F";
804        let u = Uuid::from_slice(uuid_bytes).unwrap();
805        serde_test::assert_tokens(
806            &u.compact(),
807            &[serde_test::Token::Bytes(&[
808                70, 57, 49, 54, 56, 67, 53, 69, 45, 67, 69, 66, 50, 45, 52, 70,
809            ])],
810        );
811    }
812
813    #[test]
814    fn test_de_failure() {
815        serde_test::assert_de_tokens_error::<Readable<Uuid>>(
816            &[Token::Str("hello_world")],
817            "UUID parsing failed: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `h` at 1",
818        );
819
820        serde_test::assert_de_tokens_error::<Compact<Uuid>>(
821            &[Token::Bytes(b"hello_world")],
822            "UUID parsing failed: invalid length: expected 16 bytes, found 11",
823        );
824    }
825
826    #[test]
827    fn test_serde_non_nil_uuid() {
828        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
829        let uuid = Uuid::parse_str(uuid_str).unwrap();
830        let non_nil_uuid = NonNilUuid::try_from(uuid).unwrap();
831
832        serde_test::assert_ser_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
833        serde_test::assert_de_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
834    }
835}