Skip to main content

uuid/
serde.rs

1//! Serialization and deserialization with [`serde`].
2//!
3//! Enabled via the `serde` feature flag.
4//!
5//! [`Uuid`]s are serialized as their canonical 8-4-4-4-12 lowercase hex string
6//! (e.g. `"f47ac10b-58cc-4372-a567-0e02b2c3d479"`).
7//!
8//! Deserialization accepts both the canonical string form (JSON, YAML, TOML)
9//! and a raw 16-byte buffer (bincode, messagepack).
10
11use core::fmt;
12
13use serde::{
14    Deserialize, Deserializer, Serialize, Serializer,
15    de::{self, Visitor},
16};
17
18use crate::Uuid;
19
20impl Serialize for Uuid {
21    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
22        serializer.collect_str(self)
23    }
24}
25
26struct UuidVisitor;
27
28impl<'de> Visitor<'de> for UuidVisitor {
29    type Value = Uuid;
30
31    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.write_str("a UUID as a 36-character hex string or 16-byte buffer")
33    }
34
35    fn visit_str<E: de::Error>(self, v: &str) -> Result<Uuid, E> {
36        Uuid::parse(v).map_err(de::Error::custom)
37    }
38
39    fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Uuid, E> {
40        // serde_json forwards string content here as 36 raw bytes;
41        // binary formats (bincode, msgpack) pass the raw 16-byte buffer.
42        match v.len() {
43            16 => Uuid::from_slice(v).map_err(de::Error::custom),
44            36 => Uuid::parse(v).map_err(de::Error::custom),
45            _ => Err(de::Error::custom("expected 16 bytes (binary) or 36 bytes (hex string)")),
46        }
47    }
48}
49
50impl<'de> Deserialize<'de> for Uuid {
51    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Uuid, D::Error> {
52        deserializer.deserialize_bytes(UuidVisitor)
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use serde_json;
59
60    use super::*;
61
62    const S: &str = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
63
64    #[test]
65    fn round_trip() {
66        let uuid = Uuid::parse(S).unwrap();
67        let json = serde_json::to_string(&uuid).unwrap();
68        assert_eq!(json, format!("\"{S}\""));
69        let got: Uuid = serde_json::from_str(&json).unwrap();
70        assert_eq!(got, uuid);
71    }
72
73    #[test]
74    fn deserialize_from_str() {
75        let json = format!("\"{S}\"");
76        let uuid: Uuid = serde_json::from_str(&json).unwrap();
77        assert_eq!(uuid.to_string(), S);
78    }
79
80    #[test]
81    fn deserialize_array_rejected() {
82        let json = "[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]";
83        let result: Result<Uuid, _> = serde_json::from_str(json);
84        assert!(result.is_err());
85    }
86
87    #[test]
88    fn nil_round_trip() {
89        let uuid = Uuid::nil();
90        let json = serde_json::to_string(&uuid).unwrap();
91        assert_eq!(json, "\"00000000-0000-0000-0000-000000000000\"");
92        let got: Uuid = serde_json::from_str(&json).unwrap();
93        assert_eq!(got, uuid);
94    }
95}