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 a [`Uuid`] as [`uuid::fmt::Simple`].
364///
365/// [`Uuid`]: ../../struct.Uuid.html
366///
367/// ## Examples
368///
369/// Serialize and deserialize using the simple format, failing to deserialize
370/// any other format:
371///
372/// ```
373/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
374/// struct StructA {
375///     #[serde(with = "uuid::serde::simple")]
376///     id: uuid::Uuid,
377/// }
378/// ```
379///
380/// Serialize using the simple format, but deserialize any format:
381///
382/// ```
383/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
384/// struct StructB {
385///     #[serde(serialize_with = "uuid::serde::simple::serialize")]
386///     id: uuid::Uuid,
387/// }
388/// ```
389pub mod simple {
390    use super::*;
391
392    /// Serialize a [`Uuid`] as a simple string.
393    ///
394    /// [`Uuid`]: ../../struct.Uuid.html
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// #[derive(serde_derive::Serialize)]
400    /// struct Struct {
401    ///     #[serde(serialize_with = "uuid::serde::simple::serialize")]
402    ///     id: uuid::Uuid,
403    /// }
404    ///
405    /// ```
406    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
407    where
408        S: serde_core::Serializer,
409    {
410        serde_core::Serialize::serialize(u.as_simple(), serializer)
411    }
412
413    /// Deserialize a simple-formatted string as a [`Uuid`].
414    ///
415    /// [`Uuid`]: ../../struct.Uuid.html
416    pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
417    where
418        D: serde_core::Deserializer<'de>,
419    {
420        Ok(Simple::deserialize(deserializer)?.into())
421    }
422
423    #[cfg(test)]
424    mod tests {
425        use serde::de::{self, Error};
426        use serde_test::{Readable, Token};
427
428        use super::*;
429
430        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
431        const SIMPLE_UUID_STR: &str = "f9168c5eceb24faab6bf329bf39fa1e4";
432
433        #[test]
434        fn test_serialize_as_simple() {
435            #[derive(serde_derive::Serialize)]
436            struct Struct(#[serde(with = "super")] crate::Uuid);
437
438            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
439            serde_test::assert_ser_tokens(
440                &u,
441                &[
442                    Token::NewtypeStruct { name: "Struct" },
443                    Token::Str(SIMPLE_UUID_STR),
444                ],
445            );
446        }
447
448        #[test]
449        fn test_de_from_simple() {
450            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
451            struct Struct(#[serde(with = "super")] crate::Uuid);
452            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
453            serde_test::assert_de_tokens::<Struct>(
454                &s,
455                &[
456                    Token::TupleStruct {
457                        name: "Struct",
458                        len: 1,
459                    },
460                    Token::BorrowedStr(SIMPLE_UUID_STR),
461                    Token::TupleStructEnd,
462                ],
463            );
464        }
465
466        #[test]
467        fn test_de_reject_hyphenated() {
468            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
469            struct Struct(#[serde(with = "super")] crate::Uuid);
470            serde_test::assert_de_tokens_error::<Readable<Struct>>(
471                &[
472                    Token::TupleStruct {
473                        name: "Struct",
474                        len: 1,
475                    },
476                    Token::BorrowedStr(HYPHENATED_UUID_STR),
477                    Token::TupleStructEnd,
478                ],
479                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
480            );
481        }
482    }
483}
484
485/// Serialize a [`Uuid`] as [`uuid::fmt::Braced`].
486///
487/// [`Uuid`]: ../../struct.Uuid.html
488///
489/// ## Examples
490///
491/// Serialize and deserialize using the braced format, failing to deserialize
492/// any other format:
493///
494/// ```
495/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
496/// struct StructA {
497///     #[serde(with = "uuid::serde::braced")]
498///     id: uuid::Uuid,
499/// }
500/// ```
501///
502/// Serialize using the braced format, but deserialize any format:
503///
504/// ```
505/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
506/// struct StructB {
507///     #[serde(serialize_with = "uuid::serde::braced::serialize")]
508///     id: uuid::Uuid,
509/// }
510/// ```
511pub mod braced {
512    use super::*;
513
514    /// Serialize a [`Uuid`] as a braced string.
515    ///
516    /// [`Uuid`]: ../../struct.Uuid.html
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// #[derive(serde_derive::Serialize)]
522    /// struct Struct {
523    ///     #[serde(serialize_with = "uuid::serde::braced::serialize")]
524    ///     id: uuid::Uuid,
525    /// }
526    ///
527    /// ```
528    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
529    where
530        S: serde_core::Serializer,
531    {
532        serde_core::Serialize::serialize(u.as_braced(), serializer)
533    }
534
535    /// Deserialize a braced-formatted string as a [`Uuid`].
536    ///
537    /// [`Uuid`]: ../../struct.Uuid.html
538    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
539    where
540        D: serde_core::Deserializer<'de>,
541    {
542        Ok(Braced::deserialize(deserializer)?.into())
543    }
544
545    #[cfg(test)]
546    mod tests {
547
548        use serde::de::{self, Error};
549        use serde_test::{Readable, Token};
550
551        use super::*;
552
553        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
554        const BRACED_UUID_STR: &str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
555
556        #[test]
557        fn test_serialize_as_braced() {
558            #[derive(serde_derive::Serialize)]
559            struct Struct(#[serde(with = "super")] crate::Uuid);
560
561            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
562            serde_test::assert_ser_tokens(
563                &u,
564                &[
565                    Token::NewtypeStruct { name: "Struct" },
566                    Token::Str(BRACED_UUID_STR),
567                ],
568            );
569        }
570
571        #[test]
572        fn test_de_from_braced() {
573            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
574            struct Struct(#[serde(with = "super")] crate::Uuid);
575            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
576            serde_test::assert_de_tokens::<Struct>(
577                &s,
578                &[
579                    Token::TupleStruct {
580                        name: "Struct",
581                        len: 1,
582                    },
583                    Token::BorrowedStr(BRACED_UUID_STR),
584                    Token::TupleStructEnd,
585                ],
586            );
587        }
588
589        #[test]
590        fn test_de_reject_hyphenated() {
591            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
592            struct Struct(#[serde(with = "super")] crate::Uuid);
593            serde_test::assert_de_tokens_error::<Readable<Struct>>(
594                &[
595                    Token::TupleStruct {
596                        name: "Struct",
597                        len: 1,
598                    },
599                    Token::BorrowedStr(HYPHENATED_UUID_STR),
600                    Token::TupleStructEnd,
601                ],
602                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
603            );
604        }
605    }
606}
607
608/// Serialize a [`Uuid`] as [`uuid::fmt::Hyphenated`].
609///
610/// [`Uuid`]: ../../struct.Uuid.html
611///
612/// ## Examples
613///
614/// Serialize and deserialize using the hyphenated format, failing to deserialize
615/// any other format:
616///
617/// ```
618/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
619/// struct StructA {
620///     #[serde(with = "uuid::serde::hyphenated")]
621///     id: uuid::Uuid,
622/// }
623/// ```
624///
625/// Serialize using the hyphenated format, but deserialize any format:
626///
627/// ```
628/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
629/// struct StructB {
630///     #[serde(serialize_with = "uuid::serde::hyphenated::serialize")]
631///     id: uuid::Uuid,
632/// }
633/// ```
634pub mod hyphenated {
635
636    use super::*;
637
638    /// Serialize a [`Uuid`] as a hyphenated string.
639    ///
640    /// [`Uuid`]: ../../struct.Uuid.html
641    ///
642    /// # Examples
643    ///
644    /// ```
645    /// #[derive(serde_derive::Serialize)]
646    /// struct Struct {
647    ///     #[serde(serialize_with = "uuid::serde::hyphenated::serialize")]
648    ///     id: uuid::Uuid,
649    /// }
650    ///
651    /// ```
652    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
653    where
654        S: serde_core::Serializer,
655    {
656        serde_core::Serialize::serialize(u.as_hyphenated(), serializer)
657    }
658
659    /// Deserialize a hyphenated-formatted string as a [`Uuid`].
660    ///
661    /// [`Uuid`]: ../../struct.Uuid.html
662    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
663    where
664        D: serde_core::Deserializer<'de>,
665    {
666        Ok(Hyphenated::deserialize(deserializer)?.into())
667    }
668
669    #[cfg(test)]
670    mod tests {
671
672        use serde::de::{self, Error};
673        use serde_test::{Readable, Token};
674
675        use super::*;
676
677        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
678        const BRACED_UUID_STR: &str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
679
680        #[test]
681        fn test_serialize_as_hyphenated() {
682            #[derive(serde_derive::Serialize)]
683            struct Struct(#[serde(with = "super")] crate::Uuid);
684
685            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
686            serde_test::assert_ser_tokens(
687                &u,
688                &[
689                    Token::NewtypeStruct { name: "Struct" },
690                    Token::Str(HYPHENATED_UUID_STR),
691                ],
692            );
693        }
694
695        #[test]
696        fn test_de_from_hyphenated() {
697            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
698            struct Struct(#[serde(with = "super")] crate::Uuid);
699            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
700            serde_test::assert_de_tokens::<Struct>(
701                &s,
702                &[
703                    Token::TupleStruct {
704                        name: "Struct",
705                        len: 1,
706                    },
707                    Token::BorrowedStr(HYPHENATED_UUID_STR),
708                    Token::TupleStructEnd,
709                ],
710            );
711        }
712
713        #[test]
714        fn test_de_reject_braced() {
715            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
716            struct Struct(#[serde(with = "super")] crate::Uuid);
717            serde_test::assert_de_tokens_error::<Readable<Struct>>(
718                &[
719                    Token::TupleStruct {
720                        name: "Struct",
721                        len: 1,
722                    },
723                    Token::BorrowedStr(BRACED_UUID_STR),
724                    Token::TupleStructEnd,
725                ],
726                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 14")),
727            );
728        }
729    }
730}
731
732/// Serialize a [`Uuid`] as [`uuid::fmt::Urn`].
733///
734/// [`Uuid`]: ../../struct.Uuid.html
735///
736/// ## Examples
737///
738/// Serialize and deserialize using the URN format, failing to deserialize
739/// any other format:
740///
741/// ```
742/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
743/// struct StructA {
744///     #[serde(with = "uuid::serde::urn")]
745///     id: uuid::Uuid,
746/// }
747/// ```
748///
749/// Serialize using the URN format, but deserialize any format:
750///
751/// ```
752/// #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
753/// struct StructB {
754///     #[serde(serialize_with = "uuid::serde::urn::serialize")]
755///     id: uuid::Uuid,
756/// }
757/// ```
758pub mod urn {
759    use super::*;
760
761    /// Serialize a [`Uuid`] as a URN string.
762    ///
763    /// [`Uuid`]: ../../struct.Uuid.html
764    ///
765    /// # Examples
766    ///
767    /// ```
768    /// #[derive(serde_derive::Serialize)]
769    /// struct Struct {
770    ///     #[serde(serialize_with = "uuid::serde::urn::serialize")]
771    ///     id: uuid::Uuid,
772    /// }
773    ///
774    /// ```
775    pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
776    where
777        S: serde_core::Serializer,
778    {
779        serde_core::Serialize::serialize(u.as_urn(), serializer)
780    }
781
782    /// Deserialize a URN-formatted string as a [`Uuid`].
783    ///
784    /// [`Uuid`]: ../../struct.Uuid.html
785    pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
786    where
787        D: serde_core::Deserializer<'de>,
788    {
789        Ok(Urn::deserialize(deserializer)?.into())
790    }
791
792    #[cfg(test)]
793    mod tests {
794        use serde::de::{self, Error};
795        use serde_test::{Readable, Token};
796
797        use super::*;
798
799        const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
800        const URN_UUID_STR: &str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
801
802        #[test]
803        fn test_serialize_as_urn() {
804            #[derive(serde_derive::Serialize)]
805            struct Struct(#[serde(with = "super")] crate::Uuid);
806
807            let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
808            serde_test::assert_ser_tokens(
809                &u,
810                &[
811                    Token::NewtypeStruct { name: "Struct" },
812                    Token::Str(URN_UUID_STR),
813                ],
814            );
815        }
816
817        #[test]
818        fn test_de_from_urn() {
819            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
820            struct Struct(#[serde(with = "super")] crate::Uuid);
821            let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
822            serde_test::assert_de_tokens::<Struct>(
823                &s,
824                &[
825                    Token::TupleStruct {
826                        name: "Struct",
827                        len: 1,
828                    },
829                    Token::BorrowedStr(URN_UUID_STR),
830                    Token::TupleStructEnd,
831                ],
832            );
833        }
834
835        #[test]
836        fn test_de_reject_hyphenated() {
837            #[derive(PartialEq, Debug, serde_derive::Deserialize)]
838            struct Struct(#[serde(with = "super")] crate::Uuid);
839            serde_test::assert_de_tokens_error::<Readable<Struct>>(
840                &[
841                    Token::TupleStruct {
842                        name: "Struct",
843                        len: 1,
844                    },
845                    Token::BorrowedStr(HYPHENATED_UUID_STR),
846                    Token::TupleStructEnd,
847                ],
848                &format!("{}", de::value::Error::custom("UUID parsing failed: invalid group length in group 4: expected 12, found 12")),
849            );
850        }
851    }
852}
853
854#[cfg(test)]
855mod serde_tests {
856    use super::*;
857
858    use serde_test::{Compact, Configure, Readable, Token};
859
860    #[test]
861    fn test_serialize_readable_string() {
862        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
863        let u = Uuid::parse_str(uuid_str).unwrap();
864        serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]);
865    }
866
867    #[test]
868    fn test_deserialize_readable_compact() {
869        let uuid_bytes = b"F9168C5E-CEB2-4F";
870        let u = Uuid::from_slice(uuid_bytes).unwrap();
871
872        serde_test::assert_de_tokens(
873            &u.readable(),
874            &[
875                serde_test::Token::Tuple { len: 16 },
876                serde_test::Token::U8(uuid_bytes[0]),
877                serde_test::Token::U8(uuid_bytes[1]),
878                serde_test::Token::U8(uuid_bytes[2]),
879                serde_test::Token::U8(uuid_bytes[3]),
880                serde_test::Token::U8(uuid_bytes[4]),
881                serde_test::Token::U8(uuid_bytes[5]),
882                serde_test::Token::U8(uuid_bytes[6]),
883                serde_test::Token::U8(uuid_bytes[7]),
884                serde_test::Token::U8(uuid_bytes[8]),
885                serde_test::Token::U8(uuid_bytes[9]),
886                serde_test::Token::U8(uuid_bytes[10]),
887                serde_test::Token::U8(uuid_bytes[11]),
888                serde_test::Token::U8(uuid_bytes[12]),
889                serde_test::Token::U8(uuid_bytes[13]),
890                serde_test::Token::U8(uuid_bytes[14]),
891                serde_test::Token::U8(uuid_bytes[15]),
892                serde_test::Token::TupleEnd,
893            ],
894        );
895    }
896
897    #[test]
898    fn test_deserialize_readable_bytes() {
899        let uuid_bytes = b"F9168C5E-CEB2-4F";
900        let u = Uuid::from_slice(uuid_bytes).unwrap();
901
902        serde_test::assert_de_tokens(&u.readable(), &[serde_test::Token::Bytes(uuid_bytes)]);
903    }
904
905    #[test]
906    fn test_serialize_hyphenated() {
907        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
908        let u = Uuid::parse_str(uuid_str).unwrap();
909        serde_test::assert_ser_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
910        serde_test::assert_de_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
911    }
912
913    #[test]
914    fn test_serialize_simple() {
915        let uuid_str = "f9168c5eceb24faab6bf329bf39fa1e4";
916        let u = Uuid::parse_str(uuid_str).unwrap();
917        serde_test::assert_ser_tokens(&u.simple(), &[Token::Str(uuid_str)]);
918        serde_test::assert_de_tokens(&u.simple(), &[Token::Str(uuid_str)]);
919    }
920
921    #[test]
922    fn test_serialize_urn() {
923        let uuid_str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
924        let u = Uuid::parse_str(uuid_str).unwrap();
925        serde_test::assert_ser_tokens(&u.urn(), &[Token::Str(uuid_str)]);
926        serde_test::assert_de_tokens(&u.urn(), &[Token::Str(uuid_str)]);
927    }
928
929    #[test]
930    fn test_serialize_braced() {
931        let uuid_str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
932        let u = Uuid::parse_str(uuid_str).unwrap();
933        serde_test::assert_ser_tokens(&u.braced(), &[Token::Str(uuid_str)]);
934        serde_test::assert_de_tokens(&u.braced(), &[Token::Str(uuid_str)]);
935    }
936
937    #[test]
938    fn test_serialize_non_human_readable() {
939        let uuid_bytes = b"F9168C5E-CEB2-4F";
940        let u = Uuid::from_slice(uuid_bytes).unwrap();
941        serde_test::assert_tokens(
942            &u.compact(),
943            &[serde_test::Token::Bytes(&[
944                70, 57, 49, 54, 56, 67, 53, 69, 45, 67, 69, 66, 50, 45, 52, 70,
945            ])],
946        );
947    }
948
949    #[test]
950    fn test_de_failure() {
951        serde_test::assert_de_tokens_error::<Readable<Uuid>>(
952            &[Token::Str("hello_world")],
953            "UUID parsing failed: invalid character: found `h` at 1",
954        );
955
956        serde_test::assert_de_tokens_error::<Compact<Uuid>>(
957            &[Token::Bytes(b"hello_world")],
958            "UUID parsing failed: invalid length: expected 16 bytes, found 11",
959        );
960    }
961
962    #[test]
963    fn test_serde_non_nil_uuid() {
964        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
965        let uuid = Uuid::parse_str(uuid_str).unwrap();
966        let non_nil_uuid = NonNilUuid::try_from(uuid).unwrap();
967
968        serde_test::assert_ser_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
969        serde_test::assert_de_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
970    }
971}