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