1use crate::{
13 error::*,
14 fmt::{Braced, Hyphenated, Simple, Urn},
15 non_nil::NonNilUuid,
16 std::fmt,
17 Uuid,
18};
19use serde_core::{
20 de::{self, Error as _},
21 Deserialize, Deserializer, Serialize, Serializer,
22};
23
24impl Serialize for Uuid {
25 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
26 if serializer.is_human_readable() {
27 serializer.serialize_str(self.hyphenated().encode_lower(&mut Uuid::encode_buffer()))
28 } else {
29 serializer.serialize_bytes(self.as_bytes())
30 }
31 }
32}
33
34impl Serialize for NonNilUuid {
35 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36 where
37 S: serde_core::Serializer,
38 {
39 Uuid::from(*self).serialize(serializer)
40 }
41}
42
43impl Serialize for Hyphenated {
44 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
45 serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
46 }
47}
48
49impl Serialize for Simple {
50 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
51 serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
52 }
53}
54
55impl Serialize for Urn {
56 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
57 serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
58 }
59}
60
61impl Serialize for Braced {
62 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63 serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer()))
64 }
65}
66
67impl<'de> Deserialize<'de> for Uuid {
68 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
69 fn de_error<E: de::Error>(e: Error) -> E {
70 E::custom(format_args!("UUID parsing failed: {}", e))
71 }
72
73 if deserializer.is_human_readable() {
74 struct UuidVisitor;
75
76 impl<'vi> de::Visitor<'vi> for UuidVisitor {
77 type Value = Uuid;
78
79 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(formatter, "a UUID string")
81 }
82
83 fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
84 value.parse::<Uuid>().map_err(de_error)
85 }
86
87 fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Uuid, E> {
88 Uuid::from_slice(value).map_err(de_error)
89 }
90
91 fn visit_seq<A>(self, mut seq: A) -> Result<Uuid, A::Error>
92 where
93 A: de::SeqAccess<'vi>,
94 {
95 #[rustfmt::skip]
96 let bytes = [
97 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(0, &self)) },
98 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(1, &self)) },
99 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(2, &self)) },
100 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(3, &self)) },
101 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(4, &self)) },
102 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(5, &self)) },
103 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(6, &self)) },
104 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(7, &self)) },
105 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(8, &self)) },
106 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(9, &self)) },
107 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(10, &self)) },
108 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(11, &self)) },
109 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(12, &self)) },
110 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(13, &self)) },
111 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(14, &self)) },
112 match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(15, &self)) },
113 ];
114
115 Ok(Uuid::from_bytes(bytes))
116 }
117 }
118
119 deserializer.deserialize_str(UuidVisitor)
120 } else {
121 struct UuidBytesVisitor;
122
123 impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
124 type Value = Uuid;
125
126 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(formatter, "bytes")
128 }
129
130 fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Uuid, E> {
131 Uuid::from_slice(value).map_err(de_error)
132 }
133 }
134
135 deserializer.deserialize_bytes(UuidBytesVisitor)
136 }
137 }
138}
139
140impl<'de> Deserialize<'de> for NonNilUuid {
141 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
142 where
143 D: serde_core::Deserializer<'de>,
144 {
145 let uuid = Uuid::deserialize(deserializer)?;
146
147 NonNilUuid::try_from(uuid).map_err(|_| {
148 de::Error::invalid_value(de::Unexpected::Other("nil UUID"), &"a non-nil UUID")
149 })
150 }
151}
152
153enum ExpectedFormat {
154 Simple,
155 Braced,
156 Urn,
157}
158
159impl std::fmt::Display for ExpectedFormat {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 let s = match self {
162 ExpectedFormat::Simple => "a simple Uuid string like 67e5504410b1426f9247bb680e5fe0c8",
163 ExpectedFormat::Braced => {
164 "a braced Uuid string like {67e55044-10b1-426f-9247-bb680e5fe0c8}"
165 }
166 ExpectedFormat::Urn => {
167 "a URN Uuid string like urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8"
168 }
169 };
170 f.write_str(s)
171 }
172}
173
174impl de::Expected for ExpectedFormat {
175 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
176 <ExpectedFormat as std::fmt::Display>::fmt(self, formatter)
177 }
178}
179
180pub mod compact {
181 pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
189 where
190 S: serde_core::Serializer,
191 {
192 serde_core::Serialize::serialize(u.as_bytes(), serializer)
193 }
194
195 pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
199 where
200 D: serde_core::Deserializer<'de>,
201 {
202 let bytes: [u8; 16] = serde_core::Deserialize::deserialize(deserializer)?;
203
204 Ok(crate::Uuid::from_bytes(bytes))
205 }
206
207 #[cfg(test)]
208 mod tests {
209 use serde_derive::*;
210 use serde_test::Configure;
211
212 #[test]
213 fn test_serialize_compact() {
214 #[derive(Serialize, Debug, Deserialize, PartialEq)]
215 struct UuidContainer {
216 #[serde(with = "crate::serde::compact")]
217 u: crate::Uuid,
218 }
219
220 let uuid_bytes = b"F9168C5E-CEB2-4F";
221 let container = UuidContainer {
222 u: crate::Uuid::from_slice(uuid_bytes).unwrap(),
223 };
224
225 serde_test::assert_tokens(
228 &container.compact(),
229 &[
230 serde_test::Token::Struct {
231 name: "UuidContainer",
232 len: 1,
233 },
234 serde_test::Token::Str("u"),
235 serde_test::Token::Tuple { len: 16 },
236 serde_test::Token::U8(uuid_bytes[0]),
237 serde_test::Token::U8(uuid_bytes[1]),
238 serde_test::Token::U8(uuid_bytes[2]),
239 serde_test::Token::U8(uuid_bytes[3]),
240 serde_test::Token::U8(uuid_bytes[4]),
241 serde_test::Token::U8(uuid_bytes[5]),
242 serde_test::Token::U8(uuid_bytes[6]),
243 serde_test::Token::U8(uuid_bytes[7]),
244 serde_test::Token::U8(uuid_bytes[8]),
245 serde_test::Token::U8(uuid_bytes[9]),
246 serde_test::Token::U8(uuid_bytes[10]),
247 serde_test::Token::U8(uuid_bytes[11]),
248 serde_test::Token::U8(uuid_bytes[12]),
249 serde_test::Token::U8(uuid_bytes[13]),
250 serde_test::Token::U8(uuid_bytes[14]),
251 serde_test::Token::U8(uuid_bytes[15]),
252 serde_test::Token::TupleEnd,
253 serde_test::Token::StructEnd,
254 ],
255 )
256 }
257 }
258}
259
260pub mod simple {
282 use serde_core::{de, Deserialize};
283
284 use crate::{parser::parse_simple, Uuid};
285
286 use super::ExpectedFormat;
287
288 pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
304 where
305 S: serde_core::Serializer,
306 {
307 serde_core::Serialize::serialize(u.as_simple(), serializer)
308 }
309
310 pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
314 where
315 D: serde_core::Deserializer<'de>,
316 {
317 let s = <&str as Deserialize>::deserialize(deserializer)?;
318 let bytes = parse_simple(s.as_bytes()).map_err(|_| {
319 de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Simple)
320 })?;
321 Ok(Uuid::from_bytes(bytes))
322 }
323
324 #[cfg(test)]
325 mod tests {
326 use serde::de::{self, Error};
327 use serde_test::{Readable, Token};
328
329 use crate::{external::serde_support::ExpectedFormat, Uuid};
330
331 const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
332 const SIMPLE_UUID_STR: &str = "f9168c5eceb24faab6bf329bf39fa1e4";
333
334 #[test]
335 fn test_serialize_as_simple() {
336 #[derive(serde_derive::Serialize)]
337 struct Struct(#[serde(with = "super")] crate::Uuid);
338
339 let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
340 serde_test::assert_ser_tokens(
341 &u,
342 &[
343 Token::NewtypeStruct { name: "Struct" },
344 Token::Str(SIMPLE_UUID_STR),
345 ],
346 );
347 }
348
349 #[test]
350 fn test_de_from_simple() {
351 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
352 struct Struct(#[serde(with = "super")] crate::Uuid);
353 let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
354 serde_test::assert_de_tokens::<Struct>(
355 &s,
356 &[
357 Token::TupleStruct {
358 name: "Struct",
359 len: 1,
360 },
361 Token::BorrowedStr(SIMPLE_UUID_STR),
362 Token::TupleStructEnd,
363 ],
364 );
365 }
366
367 #[test]
368 fn test_de_reject_hypenated() {
369 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
370 struct Struct(#[serde(with = "super")] crate::Uuid);
371 serde_test::assert_de_tokens_error::<Readable<Struct>>(
372 &[
373 Token::TupleStruct {
374 name: "Struct",
375 len: 1,
376 },
377 Token::BorrowedStr(HYPHENATED_UUID_STR),
378 Token::TupleStructEnd,
379 ],
380 &format!(
381 "{}",
382 de::value::Error::invalid_value(
383 de::Unexpected::Str(HYPHENATED_UUID_STR),
384 &ExpectedFormat::Simple,
385 )
386 ),
387 );
388 }
389 }
390}
391
392pub mod braced {
414 use serde_core::{de, Deserialize};
415
416 use crate::parser::parse_braced;
417
418 use super::ExpectedFormat;
419
420 pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
436 where
437 S: serde_core::Serializer,
438 {
439 serde_core::Serialize::serialize(u.as_braced(), serializer)
440 }
441
442 pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
446 where
447 D: serde_core::Deserializer<'de>,
448 {
449 let s = <&str as Deserialize>::deserialize(deserializer)?;
450 let bytes = parse_braced(s.as_bytes()).map_err(|_| {
451 de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Braced)
452 })?;
453 Ok(crate::Uuid::from_bytes(bytes))
454 }
455
456 #[cfg(test)]
457 mod tests {
458 use serde::de::{self, Error};
459 use serde_test::{Readable, Token};
460
461 use crate::{external::serde_support::ExpectedFormat, Uuid};
462
463 const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
464 const BRACED_UUID_STR: &str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
465
466 #[test]
467 fn test_serialize_as_braced() {
468 #[derive(serde_derive::Serialize)]
469 struct Struct(#[serde(with = "super")] crate::Uuid);
470
471 let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
472 serde_test::assert_ser_tokens(
473 &u,
474 &[
475 Token::NewtypeStruct { name: "Struct" },
476 Token::Str(BRACED_UUID_STR),
477 ],
478 );
479 }
480
481 #[test]
482 fn test_de_from_braced() {
483 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
484 struct Struct(#[serde(with = "super")] crate::Uuid);
485 let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
486 serde_test::assert_de_tokens::<Struct>(
487 &s,
488 &[
489 Token::TupleStruct {
490 name: "Struct",
491 len: 1,
492 },
493 Token::BorrowedStr(BRACED_UUID_STR),
494 Token::TupleStructEnd,
495 ],
496 );
497 }
498
499 #[test]
500 fn test_de_reject_hypenated() {
501 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
502 struct Struct(#[serde(with = "super")] crate::Uuid);
503 serde_test::assert_de_tokens_error::<Readable<Struct>>(
504 &[
505 Token::TupleStruct {
506 name: "Struct",
507 len: 1,
508 },
509 Token::BorrowedStr(HYPHENATED_UUID_STR),
510 Token::TupleStructEnd,
511 ],
512 &format!(
513 "{}",
514 de::value::Error::invalid_value(
515 de::Unexpected::Str(HYPHENATED_UUID_STR),
516 &ExpectedFormat::Braced,
517 )
518 ),
519 );
520 }
521 }
522}
523
524pub mod urn {
546 use serde_core::{de, Deserialize};
547
548 use crate::parser::parse_urn;
549
550 use super::ExpectedFormat;
551
552 pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
568 where
569 S: serde_core::Serializer,
570 {
571 serde_core::Serialize::serialize(u.as_urn(), serializer)
572 }
573
574 pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error>
578 where
579 D: serde_core::Deserializer<'de>,
580 {
581 let s = <&str as Deserialize>::deserialize(deserializer)?;
582 let bytes = parse_urn(s.as_bytes())
583 .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Urn))?;
584 Ok(crate::Uuid::from_bytes(bytes))
585 }
586
587 #[cfg(test)]
588 mod tests {
589 use serde::de::{self, Error};
590 use serde_test::{Readable, Token};
591
592 use crate::{external::serde_support::ExpectedFormat, Uuid};
593
594 const HYPHENATED_UUID_STR: &str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
595 const URN_UUID_STR: &str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
596
597 #[test]
598 fn test_serialize_as_urn() {
599 #[derive(serde_derive::Serialize)]
600 struct Struct(#[serde(with = "super")] crate::Uuid);
601
602 let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap());
603 serde_test::assert_ser_tokens(
604 &u,
605 &[
606 Token::NewtypeStruct { name: "Struct" },
607 Token::Str(URN_UUID_STR),
608 ],
609 );
610 }
611
612 #[test]
613 fn test_de_from_urn() {
614 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
615 struct Struct(#[serde(with = "super")] crate::Uuid);
616 let s = Struct(HYPHENATED_UUID_STR.parse().unwrap());
617 serde_test::assert_de_tokens::<Struct>(
618 &s,
619 &[
620 Token::TupleStruct {
621 name: "Struct",
622 len: 1,
623 },
624 Token::BorrowedStr(URN_UUID_STR),
625 Token::TupleStructEnd,
626 ],
627 );
628 }
629
630 #[test]
631 fn test_de_reject_hypenated() {
632 #[derive(PartialEq, Debug, serde_derive::Deserialize)]
633 struct Struct(#[serde(with = "super")] crate::Uuid);
634 serde_test::assert_de_tokens_error::<Readable<Struct>>(
635 &[
636 Token::TupleStruct {
637 name: "Struct",
638 len: 1,
639 },
640 Token::BorrowedStr(HYPHENATED_UUID_STR),
641 Token::TupleStructEnd,
642 ],
643 &format!(
644 "{}",
645 de::value::Error::invalid_value(
646 de::Unexpected::Str(HYPHENATED_UUID_STR),
647 &ExpectedFormat::Urn,
648 )
649 ),
650 );
651 }
652 }
653}
654
655#[cfg(test)]
656mod serde_tests {
657 use super::*;
658
659 use serde_test::{Compact, Configure, Readable, Token};
660
661 #[test]
662 fn test_serialize_readable_string() {
663 let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
664 let u = Uuid::parse_str(uuid_str).unwrap();
665 serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]);
666 }
667
668 #[test]
669 fn test_deserialize_readable_compact() {
670 let uuid_bytes = b"F9168C5E-CEB2-4F";
671 let u = Uuid::from_slice(uuid_bytes).unwrap();
672
673 serde_test::assert_de_tokens(
674 &u.readable(),
675 &[
676 serde_test::Token::Tuple { len: 16 },
677 serde_test::Token::U8(uuid_bytes[0]),
678 serde_test::Token::U8(uuid_bytes[1]),
679 serde_test::Token::U8(uuid_bytes[2]),
680 serde_test::Token::U8(uuid_bytes[3]),
681 serde_test::Token::U8(uuid_bytes[4]),
682 serde_test::Token::U8(uuid_bytes[5]),
683 serde_test::Token::U8(uuid_bytes[6]),
684 serde_test::Token::U8(uuid_bytes[7]),
685 serde_test::Token::U8(uuid_bytes[8]),
686 serde_test::Token::U8(uuid_bytes[9]),
687 serde_test::Token::U8(uuid_bytes[10]),
688 serde_test::Token::U8(uuid_bytes[11]),
689 serde_test::Token::U8(uuid_bytes[12]),
690 serde_test::Token::U8(uuid_bytes[13]),
691 serde_test::Token::U8(uuid_bytes[14]),
692 serde_test::Token::U8(uuid_bytes[15]),
693 serde_test::Token::TupleEnd,
694 ],
695 );
696 }
697
698 #[test]
699 fn test_deserialize_readable_bytes() {
700 let uuid_bytes = b"F9168C5E-CEB2-4F";
701 let u = Uuid::from_slice(uuid_bytes).unwrap();
702
703 serde_test::assert_de_tokens(&u.readable(), &[serde_test::Token::Bytes(uuid_bytes)]);
704 }
705
706 #[test]
707 fn test_serialize_hyphenated() {
708 let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
709 let u = Uuid::parse_str(uuid_str).unwrap();
710 serde_test::assert_ser_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]);
711 }
712
713 #[test]
714 fn test_serialize_simple() {
715 let uuid_str = "f9168c5eceb24faab6bf329bf39fa1e4";
716 let u = Uuid::parse_str(uuid_str).unwrap();
717 serde_test::assert_ser_tokens(&u.simple(), &[Token::Str(uuid_str)]);
718 }
719
720 #[test]
721 fn test_serialize_urn() {
722 let uuid_str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
723 let u = Uuid::parse_str(uuid_str).unwrap();
724 serde_test::assert_ser_tokens(&u.urn(), &[Token::Str(uuid_str)]);
725 }
726
727 #[test]
728 fn test_serialize_braced() {
729 let uuid_str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}";
730 let u = Uuid::parse_str(uuid_str).unwrap();
731 serde_test::assert_ser_tokens(&u.braced(), &[Token::Str(uuid_str)]);
732 }
733
734 #[test]
735 fn test_serialize_non_human_readable() {
736 let uuid_bytes = b"F9168C5E-CEB2-4F";
737 let u = Uuid::from_slice(uuid_bytes).unwrap();
738 serde_test::assert_tokens(
739 &u.compact(),
740 &[serde_test::Token::Bytes(&[
741 70, 57, 49, 54, 56, 67, 53, 69, 45, 67, 69, 66, 50, 45, 52, 70,
742 ])],
743 );
744 }
745
746 #[test]
747 fn test_de_failure() {
748 serde_test::assert_de_tokens_error::<Readable<Uuid>>(
749 &[Token::Str("hello_world")],
750 "UUID parsing failed: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `h` at 1",
751 );
752
753 serde_test::assert_de_tokens_error::<Compact<Uuid>>(
754 &[Token::Bytes(b"hello_world")],
755 "UUID parsing failed: invalid length: expected 16 bytes, found 11",
756 );
757 }
758
759 #[test]
760 fn test_serde_non_nil_uuid() {
761 let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
762 let uuid = Uuid::parse_str(uuid_str).unwrap();
763 let non_nil_uuid = NonNilUuid::try_from(uuid).unwrap();
764
765 serde_test::assert_ser_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
766 serde_test::assert_de_tokens(&non_nil_uuid.readable(), &[Token::Str(uuid_str)]);
767 }
768}