bson/
uuid.rs

1//! UUID support for BSON.
2//!
3//! ## The [`crate::Uuid`] type
4//!
5//! The BSON format supports UUIDs via the "binary" type with the UUID subtype (4).
6//! To facilitate working with these UUID-subtyped binary values, this crate provides a
7//! [`crate::Uuid`] type, whose `serde` implementation automatically serializes to and deserializes
8//! from binary values with subtype 4.
9//!
10//! The popular [`uuid`](https://docs.rs/uuid) crate also provides a
11//! [UUID type](https://docs.rs/uuid/latest/uuid/struct.Uuid.html),
12//! though its `serde` implementation does not produce or parse subtype 4
13//! binary values. Instead, when serialized with `bson::to_bson`, it produces as a string, and when
14//! serialized with `bson::to_vec`, it produces a binary value with subtype _0_ rather than 4.
15//! Because of this, it is highly recommended to use the [`crate::Uuid`] type when working with BSON
16//! instead of the `uuid` crate's [`Uuid`], since [`crate::Uuid`] correctly produces subtype 4
17//! binary values via either serialization function.
18//!
19//! e.g.
20//!
21//! ``` rust
22//! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
23//! # {
24//! # use uuid as uuid;
25//! use bson::doc;
26//! use serde::{Serialize, Deserialize};
27//! use serde_with::serde_as;
28//!
29//!
30//! #[serde_as]
31//! #[derive(Serialize, Deserialize)]
32//! struct Foo {
33//!     /// serializes as a String or subtype 0 BSON binary, depending
34//!     /// on whether `bson::to_bson` or `bson::to_vec` is used.
35//!     uuid: uuid::Uuid,
36//!
37//!     /// serializes as a BSON binary with subtype 4 when either is used.
38//!     bson_uuid: bson::Uuid,
39//!
40//!     /// serializes as a BSON binary with subtype 4 when either is used.
41//!     /// this requires the "uuid-1" and "serde_with-3" feature flags
42//!     #[serde_as(as = "bson::serde_helpers::uuid_1::AsBinary")]
43//!     uuid_as_bson: uuid::Uuid,
44//! }
45//! # };
46//! ```
47//!
48//! ## The `uuid-1` feature flag
49//!
50//! To facilitate the conversion between [`crate::Uuid`] values and the `uuid` crate's [`Uuid`]
51//! values, the `uuid-1` feature flag can be enabled. This flag exposes a number of convenient
52//! conversions, including the `crate::Uuid::to_uuid_1` method and the `From<uuid::Uuid>`
53//! implementation for [`Bson`], which allows the `uuid` crate's [`Uuid`] values to be used in the
54//! `doc!` and `bson!` macros.
55//!
56//! ```
57//! # #[cfg(feature = "uuid-1")]
58//! # {
59//! # use uuid as uuid;
60//! use bson::doc;
61//!
62//! // this automatic conversion does not require any feature flags
63//! let query = doc! {
64//!     "uuid": bson::Uuid::new(),
65//! };
66//!
67//! // but this automatic conversion requires the "uuid-1" feature flag
68//! let query = doc! {
69//!     "uuid": uuid::Uuid::new_v4(),
70//! };
71//!
72//! // this also requires the "uuid-1" feature flag.
73//! let uuid = bson::Uuid::new().to_uuid_1();
74//! # };
75//! ```
76//!
77//! ## Serde conversion
78//!
79//! Fields using the [`uuid::Uuid`] type can be (de)serialized as BSON using the converters provided
80//! in [`serde_helpers`](crate::serde_helpers):
81//!
82//! ```
83//! # #[cfg(feature = "uuid-1")]
84//! # {
85//! use uuid;
86//! use serde::{Deserialize, Serialize};
87//! use bson::{doc, serde_helpers::uuid_1};
88//! #[derive(Deserialize, Serialize, PartialEq, Debug)]
89//! struct Foo {
90//!   /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization
91//!   #[serde(with = "uuid_1::AsBinary")]
92//!   as_bson: uuid::Uuid,
93//! }
94//!
95//! let foo = Foo {
96//!   as_bson: uuid::Uuid::new_v4(),
97//! };
98//!
99//! let expected = doc! {
100//!   "as_bson": bson::Uuid::from(foo.as_bson),
101//! };
102//!
103//! assert_eq!(bson::serialize_to_document(&foo)?, expected);
104//! # }
105//! # Ok::<(), Box<dyn std::error::Error>>(())
106//! ```
107//!
108//! ## The `serde_with-3` feature flag
109//!
110//! The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for
111//! conversions. The main benefit of this compared to the regular `serde_helpers` is that
112//! `serde_with-3` can handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former
113//! only works on fields that are exactly [`uuid::Uuid`].
114//! ```
115//! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))]
116//! # {
117//! # use uuid;
118//! use serde::{Deserialize, Serialize};
119//! use bson::{doc, serde_helpers::uuid_1};
120//!
121//! #[serde_with::serde_as]
122//! #[derive(Deserialize, Serialize, PartialEq, Debug)]
123//! struct Foo {
124//!   /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization
125//!   #[serde_as(as = "Option<uuid_1::AsBinary>")]
126//!   as_bson: Option<uuid::Uuid>,
127//! }
128//!
129//! let foo = Foo {
130//!   as_bson: Some(uuid::Uuid::new_v4()),
131//! };
132//!
133//! let expected = doc! {
134//!   "as_bson": bson::Uuid::from(foo.as_bson.unwrap()),
135//! };
136//!
137//! assert_eq!(bson::serialize_to_document(&foo)?, expected);
138//! # }
139//! # Ok::<(), Box<dyn std::error::Error>>(())
140//! ```
141//!
142//! ## Using [`crate::Uuid`] with non-BSON formats
143//!
144//! [`crate::Uuid`]'s `serde` implementation is the same as [`uuid::Uuid`]'s
145//! for non-BSON formats such as JSON:
146//! ``` rust
147//! # #[cfg(feature = "uuid-1")]
148//! # {
149//! # use uuid as uuid;
150//! # use serde::{Serialize, Deserialize};
151//! # #[derive(Serialize, Deserialize)]
152//! # struct Foo {
153//! #   uuid: uuid::Uuid,
154//! #   bson_uuid: bson::Uuid,
155//! # }
156//! use serde_json::json;
157//!
158//! let uuid = uuid::Uuid::new_v4();
159//! let bson_uuid: bson::Uuid = uuid.into();
160//! let foo = Foo { uuid, bson_uuid, };
161//!
162//! let json = serde_json::to_value(&foo)?;
163//! assert_eq!(json, json!({ "uuid": uuid.to_string(), "bson_uuid": uuid.to_string() }));
164//! # }
165//! # Ok::<(), Box::<dyn std::error::Error>>(())
166//! ```
167#[cfg(test)]
168mod test;
169
170use std::{
171    fmt::{self, Display},
172    str::FromStr,
173};
174
175use crate::{
176    error::{Error, Result},
177    spec::BinarySubtype,
178    Binary,
179    Bson,
180};
181
182/// Special type name used in the [`Uuid`] serialization implementation to indicate a BSON
183/// UUID is being serialized or deserialized. The BSON serializers/deserializers will handle this
184/// name specially, but other serializers/deserializers will just ignore it and use [`uuid::Uuid`]'s
185/// serde integration.
186#[cfg(feature = "serde")]
187pub(crate) const UUID_NEWTYPE_NAME: &str = "$__bson_private_uuid";
188
189/// A struct modeling a BSON UUID value (i.e. a Binary value with subtype 4).
190///
191/// This type should be used instead of [`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html)
192/// when serializing to or deserializing from BSON, since
193/// [`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html)'s `serde` implementation doesn't
194/// produce or parse BSON UUIDs.
195///
196/// To enable interop with the [`Uuid`] type from the `uuid` crate, enable the `uuid-0_8` feature
197/// flag.
198///
199/// For more information on the usage of this type, see the [`uuid`] module-level documentation.
200///
201/// Note: due to an issue in serde (see [here](https://github.com/serde-rs/serde/issues/2106)), this type
202/// will also allow deserialization from 16 byte + subtype 0 Binary values in BSON if part of a
203/// `#[serde(flatten)]` chain. This behavior shouldn't be relied upon as it may be fixed at some
204/// point in the future.
205#[derive(Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
206pub struct Uuid {
207    uuid: uuid::Uuid,
208}
209
210impl Uuid {
211    /// Creates a random UUID.
212    ///
213    /// This uses the operating system's RNG as the source of random numbers. If you'd like to use a
214    /// custom generator, generate random bytes and pass them to [`Uuid::from_bytes`] instead.
215    pub fn new() -> Self {
216        Self {
217            uuid: uuid::Uuid::new_v4(),
218        }
219    }
220
221    /// Creates a [`Uuid`] using the supplied big-endian bytes.
222    pub const fn from_bytes(bytes: [u8; 16]) -> Self {
223        Self::from_external_uuid(uuid::Uuid::from_bytes(bytes))
224    }
225
226    /// Creates a [`Uuid`] from the provided hex string.
227    pub fn parse_str(input: impl AsRef<str>) -> Result<Self> {
228        let uuid = uuid::Uuid::parse_str(input.as_ref()).map_err(Error::invalid_uuid_string)?;
229        Ok(Self::from_external_uuid(uuid))
230    }
231
232    pub(crate) const fn from_external_uuid(uuid: uuid::Uuid) -> Self {
233        Self { uuid }
234    }
235
236    /// Returns an array of 16 bytes containing the [`Uuid`]'s data.
237    pub const fn bytes(self) -> [u8; 16] {
238        *self.uuid.as_bytes()
239    }
240}
241
242impl Default for Uuid {
243    fn default() -> Self {
244        Self::new()
245    }
246}
247
248impl FromStr for Uuid {
249    type Err = Error;
250
251    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
252        Self::parse_str(s)
253    }
254}
255
256#[cfg(feature = "uuid-1")]
257impl Uuid {
258    /// Create a [`Uuid`] from a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
259    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
260    pub fn from_uuid_1(uuid: uuid::Uuid) -> Self {
261        Self::from_external_uuid(uuid)
262    }
263
264    /// Convert this [`Uuid`] to a [`uuid::Uuid`](https://docs.rs/uuid/0.8/uuid/struct.Uuid.html) from
265    /// the [`uuid`](https://docs.rs/uuid/0.8) crate.
266    pub fn to_uuid_1(self) -> uuid::Uuid {
267        self.uuid
268    }
269}
270
271#[cfg(feature = "serde")]
272impl serde::Serialize for Uuid {
273    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
274    where
275        S: serde::Serializer,
276    {
277        serializer.serialize_newtype_struct(UUID_NEWTYPE_NAME, &self.uuid)
278    }
279}
280
281#[cfg(feature = "serde")]
282impl<'de> serde::Deserialize<'de> for Uuid {
283    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
284    where
285        D: serde::Deserializer<'de>,
286    {
287        match deserializer.deserialize_newtype_struct(UUID_NEWTYPE_NAME, crate::de::BsonVisitor)? {
288            // Need to support deserializing from generic subtypes for non-BSON formats.
289            // When using the BSON deserializer, the newtype name will ensure the subtype is only
290            // ever BinarySubtype::Uuid.
291            Bson::Binary(b)
292                if matches!(b.subtype, BinarySubtype::Uuid | BinarySubtype::Generic) =>
293            {
294                let uuid =
295                    uuid::Uuid::from_slice(b.bytes.as_slice()).map_err(serde::de::Error::custom)?;
296                Ok(Self::from_external_uuid(uuid))
297            }
298            Bson::Binary(b) if b.subtype == BinarySubtype::UuidOld => {
299                Err(serde::de::Error::custom(
300                    "received legacy UUID (subtype 3) but expected regular UUID (subtype 4)",
301                ))
302            }
303            Bson::String(s) => {
304                use std::str::FromStr as _;
305                let uuid = uuid::Uuid::from_str(s.as_str()).map_err(serde::de::Error::custom)?;
306                Ok(Self::from_external_uuid(uuid))
307            }
308            b => Err(serde::de::Error::invalid_type(b.as_unexpected(), &"a UUID")),
309        }
310    }
311}
312
313impl Display for Uuid {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        self.uuid.fmt(f)
316    }
317}
318
319impl std::fmt::Debug for Uuid {
320    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321        std::fmt::Debug::fmt(&self.uuid, f)
322    }
323}
324
325impl From<Uuid> for Binary {
326    fn from(uuid: Uuid) -> Self {
327        Binary {
328            subtype: BinarySubtype::Uuid,
329            bytes: uuid.bytes().to_vec(),
330        }
331    }
332}
333
334impl From<Uuid> for Bson {
335    fn from(u: Uuid) -> Self {
336        Bson::Binary(u.into())
337    }
338}
339
340#[cfg(feature = "uuid-1")]
341impl From<uuid::Uuid> for Uuid {
342    fn from(u: uuid::Uuid) -> Self {
343        Self::from_uuid_1(u)
344    }
345}
346
347#[cfg(feature = "uuid-1")]
348impl From<Uuid> for uuid::Uuid {
349    fn from(s: Uuid) -> Self {
350        s.to_uuid_1()
351    }
352}
353
354/// Enum of the possible representations to use when converting between [`Uuid`] and [`Binary`].
355/// This enum is necessary because the different drivers used to have different ways of encoding
356/// UUIDs, with the BSON subtype: 0x03 (UUID old).
357/// If a UUID has been serialized with a particular representation, it MUST
358/// be deserialized with the same representation.
359///
360/// Example:
361/// ```
362/// use bson::{Binary, uuid::{Uuid, UuidRepresentation}};
363///
364/// let uuid = Uuid::parse_str("00112233445566778899AABBCCDDEEFF")?;
365/// let bin = Binary::from_uuid_with_representation(uuid, UuidRepresentation::PythonLegacy);
366///
367/// // This conversion fails, since the binary holds a PythonLegacy UUID, so we're required to specify
368/// // that.
369/// assert!(bin.to_uuid().is_err());
370///
371/// // This conversion succeeds, since we specified the correct representation.
372/// let new_uuid = bin.to_uuid_with_representation(UuidRepresentation::PythonLegacy)?;
373/// assert_eq!(new_uuid, uuid);
374///
375/// # Ok::<(), Box::<dyn std::error::Error>>(())
376/// ```
377#[non_exhaustive]
378#[derive(PartialEq, Clone, Copy, Debug)]
379pub enum UuidRepresentation {
380    /// The canonical representation of UUIDs in BSON (binary with subtype 0x04)
381    Standard,
382    /// The legacy representation of UUIDs in BSON used by the C# driver (binary subtype 0x03)
383    CSharpLegacy,
384    /// The legacy representation of UUIDs in BSON used by the Java driver (binary subtype 0x03)
385    JavaLegacy,
386    /// The legacy representation of UUIDs in BSON used by the Python driver, which is the same
387    /// format as STANDARD, but has binary subtype 0x03
388    PythonLegacy,
389}
390
391impl Binary {
392    /// Serializes a [`Uuid`] into BSON [`Binary`] type
393    pub fn from_uuid(uuid: Uuid) -> Self {
394        Binary::from(uuid)
395    }
396
397    /// Serializes a [`Uuid`] into BSON binary type and takes the desired representation as a
398    /// parameter. `Binary::from_uuid_with_representation(uuid, UuidRepresentation::Standard)` is
399    /// equivalent to `Binary::from_uuid(uuid)`.
400    ///
401    /// See the documentation for [`UuidRepresentation`] for more information on the possible
402    /// representations.
403    pub fn from_uuid_with_representation(uuid: Uuid, rep: UuidRepresentation) -> Self {
404        match rep {
405            UuidRepresentation::Standard => Binary::from_uuid(uuid),
406            UuidRepresentation::CSharpLegacy => {
407                let mut bytes = uuid.bytes().to_vec();
408                bytes[0..4].reverse();
409                bytes[4..6].reverse();
410                bytes[6..8].reverse();
411                Binary {
412                    subtype: BinarySubtype::UuidOld,
413                    bytes,
414                }
415            }
416            UuidRepresentation::PythonLegacy => Binary {
417                subtype: BinarySubtype::UuidOld,
418                bytes: uuid.bytes().to_vec(),
419            },
420            UuidRepresentation::JavaLegacy => {
421                let mut bytes = uuid.bytes().to_vec();
422                bytes[0..8].reverse();
423                bytes[8..16].reverse();
424                Binary {
425                    subtype: BinarySubtype::UuidOld,
426                    bytes,
427                }
428            }
429        }
430    }
431
432    /// Deserializes a BSON [`Binary`] type into a [`Uuid`] according to the provided
433    /// representation. If the representation does not match the [`Binary`], an error will be
434    /// returned.
435    ///
436    /// See the documentation for [`UuidRepresentation`] for more information on the possible
437    /// representations.
438    pub fn to_uuid_with_representation(&self, rep: UuidRepresentation) -> Result<Uuid> {
439        // If representation is non-standard, then its subtype must be UuidOld
440        if rep != UuidRepresentation::Standard && self.subtype != BinarySubtype::UuidOld {
441            return Err(Error::uuid_representation_mismatch(
442                rep,
443                self.subtype,
444                BinarySubtype::UuidOld,
445            ));
446        }
447        // If representation is standard, then its subtype must be Uuid
448        if rep == UuidRepresentation::Standard && self.subtype != BinarySubtype::Uuid {
449            return Err(Error::uuid_representation_mismatch(
450                rep,
451                self.subtype,
452                BinarySubtype::UuidOld,
453            ));
454        }
455        // Must be 16 bytes long
456        if self.bytes.len() != 16 {
457            return Err(Error::invalid_uuid_length(self.bytes.len()));
458        }
459        let mut buf = [0u8; 16];
460        buf.copy_from_slice(&self.bytes);
461        Ok(match rep {
462            UuidRepresentation::Standard => Uuid::from_bytes(buf),
463            UuidRepresentation::CSharpLegacy => {
464                buf[0..4].reverse();
465                buf[4..6].reverse();
466                buf[6..8].reverse();
467                Uuid::from_bytes(buf)
468            }
469            UuidRepresentation::PythonLegacy => Uuid::from_bytes(buf),
470            UuidRepresentation::JavaLegacy => {
471                buf[0..8].reverse();
472                buf[8..16].reverse();
473                Uuid::from_bytes(buf)
474            }
475        })
476    }
477
478    /// Deserializes a BSON [`Binary`] type into a [`Uuid`] using the standard
479    /// representation.
480    pub fn to_uuid(&self) -> Result<Uuid> {
481        self.to_uuid_with_representation(UuidRepresentation::Standard)
482    }
483}
484
485#[cfg(feature = "uuid-1")]
486impl From<uuid::Uuid> for Binary {
487    fn from(uuid: uuid::Uuid) -> Self {
488        Binary {
489            subtype: BinarySubtype::Uuid,
490            bytes: uuid.as_bytes().to_vec(),
491        }
492    }
493}