Skip to main content

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