diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/uuid/src/fmt.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/uuid/src/fmt.rs')
-rw-r--r-- | third_party/rust/uuid/src/fmt.rs | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/third_party/rust/uuid/src/fmt.rs b/third_party/rust/uuid/src/fmt.rs new file mode 100644 index 0000000000..92b40422a3 --- /dev/null +++ b/third_party/rust/uuid/src/fmt.rs @@ -0,0 +1,1030 @@ +// Copyright 2013-2014 The Rust Project Developers. +// Copyright 2018 The Uuid Project Developers. +// +// See the COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Adapters for alternative string formats. + +use crate::{ + std::{borrow::Borrow, fmt, ptr, str}, + Uuid, Variant, +}; + +impl std::fmt::Debug for Uuid { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + +impl fmt::Display for Uuid { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + +impl fmt::Display for Variant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Variant::NCS => write!(f, "NCS"), + Variant::RFC4122 => write!(f, "RFC4122"), + Variant::Microsoft => write!(f, "Microsoft"), + Variant::Future => write!(f, "Future"), + } + } +} + +impl fmt::LowerHex for Uuid { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self.as_hyphenated(), f) + } +} + +impl fmt::UpperHex for Uuid { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(self.as_hyphenated(), f) + } +} + +/// Format a [`Uuid`] as a hyphenated string, like +/// `67e55044-10b1-426f-9247-bb680e5fe0c8`. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Hyphenated(Uuid); + +/// Format a [`Uuid`] as a simple string, like +/// `67e5504410b1426f9247bb680e5fe0c8`. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Simple(Uuid); + +/// Format a [`Uuid`] as a URN string, like +/// `urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8`. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Urn(Uuid); + +/// Format a [`Uuid`] as a braced hyphenated string, like +/// `{67e55044-10b1-426f-9247-bb680e5fe0c8}`. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Braced(Uuid); + +impl Uuid { + /// Get a [`Hyphenated`] formatter. + #[inline] + pub const fn hyphenated(self) -> Hyphenated { + Hyphenated(self) + } + + /// Get a borrowed [`Hyphenated`] formatter. + #[inline] + pub fn as_hyphenated(&self) -> &Hyphenated { + // SAFETY: `Uuid` and `Hyphenated` have the same ABI + unsafe { &*(self as *const Uuid as *const Hyphenated) } + } + + /// Get a [`Simple`] formatter. + #[inline] + pub const fn simple(self) -> Simple { + Simple(self) + } + + /// Get a borrowed [`Simple`] formatter. + #[inline] + pub fn as_simple(&self) -> &Simple { + // SAFETY: `Uuid` and `Simple` have the same ABI + unsafe { &*(self as *const Uuid as *const Simple) } + } + + /// Get a [`Urn`] formatter. + #[inline] + pub const fn urn(self) -> Urn { + Urn(self) + } + + /// Get a borrowed [`Urn`] formatter. + #[inline] + pub fn as_urn(&self) -> &Urn { + // SAFETY: `Uuid` and `Urn` have the same ABI + unsafe { &*(self as *const Uuid as *const Urn) } + } + + /// Get a [`Braced`] formatter. + #[inline] + pub const fn braced(self) -> Braced { + Braced(self) + } + + /// Get a borrowed [`Braced`] formatter. + #[inline] + pub fn as_braced(&self) -> &Braced { + // SAFETY: `Uuid` and `Braced` have the same ABI + unsafe { &*(self as *const Uuid as *const Braced) } + } +} + +const UPPER: [u8; 16] = [ + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F', +]; +const LOWER: [u8; 16] = [ + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f', +]; + +#[inline] +const fn format_simple(src: &[u8; 16], upper: bool) -> [u8; 32] { + let lut = if upper { &UPPER } else { &LOWER }; + let mut dst = [0; 32]; + let mut i = 0; + while i < 16 { + let x = src[i]; + dst[i * 2] = lut[(x >> 4) as usize]; + dst[i * 2 + 1] = lut[(x & 0x0f) as usize]; + i += 1; + } + dst +} + +#[inline] +const fn format_hyphenated(src: &[u8; 16], upper: bool) -> [u8; 36] { + let lut = if upper { &UPPER } else { &LOWER }; + let groups = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)]; + let mut dst = [0; 36]; + + let mut group_idx = 0; + let mut i = 0; + while group_idx < 5 { + let (start, end) = groups[group_idx]; + let mut j = start; + while j < end { + let x = src[i]; + i += 1; + + dst[j] = lut[(x >> 4) as usize]; + dst[j + 1] = lut[(x & 0x0f) as usize]; + j += 2; + } + if group_idx < 4 { + dst[end] = b'-'; + } + group_idx += 1; + } + dst +} + +#[inline] +fn encode_simple<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { + let buf = &mut buffer[..Simple::LENGTH]; + let dst = buf.as_mut_ptr(); + + // SAFETY: `buf` is guaranteed to be at least `LEN` bytes + // SAFETY: The encoded buffer is ASCII encoded + unsafe { + ptr::write(dst.cast(), format_simple(src, upper)); + str::from_utf8_unchecked_mut(buf) + } +} + +#[inline] +fn encode_hyphenated<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { + let buf = &mut buffer[..Hyphenated::LENGTH]; + let dst = buf.as_mut_ptr(); + + // SAFETY: `buf` is guaranteed to be at least `LEN` bytes + // SAFETY: The encoded buffer is ASCII encoded + unsafe { + ptr::write(dst.cast(), format_hyphenated(src, upper)); + str::from_utf8_unchecked_mut(buf) + } +} + +#[inline] +fn encode_braced<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { + let buf = &mut buffer[..Braced::LENGTH]; + buf[0] = b'{'; + buf[Braced::LENGTH - 1] = b'}'; + + // SAFETY: `buf` is guaranteed to be at least `LEN` bytes + // SAFETY: The encoded buffer is ASCII encoded + unsafe { + let dst = buf.as_mut_ptr().add(1); + + ptr::write(dst.cast(), format_hyphenated(src, upper)); + str::from_utf8_unchecked_mut(buf) + } +} + +#[inline] +fn encode_urn<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { + let buf = &mut buffer[..Urn::LENGTH]; + buf[..9].copy_from_slice(b"urn:uuid:"); + + // SAFETY: `buf` is guaranteed to be at least `LEN` bytes + // SAFETY: The encoded buffer is ASCII encoded + unsafe { + let dst = buf.as_mut_ptr().add(9); + + ptr::write(dst.cast(), format_hyphenated(src, upper)); + str::from_utf8_unchecked_mut(buf) + } +} + +impl Hyphenated { + /// The length of a hyphenated [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 36; + + /// Creates a [`Hyphenated`] from a [`Uuid`]. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`Hyphenated`]: struct.Hyphenated.html + pub const fn from_uuid(uuid: Uuid) -> Self { + Hyphenated(uuid) + } + + /// Writes the [`Uuid`] as a lower-case hyphenated string to + /// `buffer`, and returns the subslice of the buffer that contains the + /// encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.hyphenated() + /// .encode_lower(&mut Uuid::encode_buffer()), + /// "936da01f-9abd-4d9d-80c7-02af85c822a8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 40]; + /// uuid.hyphenated().encode_lower(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_hyphenated(self.0.as_bytes(), buffer, false) + } + + /// Writes the [`Uuid`] as an upper-case hyphenated string to + /// `buffer`, and returns the subslice of the buffer that contains the + /// encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.hyphenated() + /// .encode_upper(&mut Uuid::encode_buffer()), + /// "936DA01F-9ABD-4D9D-80C7-02AF85C822A8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 40]; + /// uuid.hyphenated().encode_upper(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_hyphenated(self.0.as_bytes(), buffer, true) + } + + /// Get a reference to the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let hyphenated = Uuid::nil().hyphenated(); + /// assert_eq!(*hyphenated.as_uuid(), Uuid::nil()); + /// ``` + pub const fn as_uuid(&self) -> &Uuid { + &self.0 + } + + /// Consumes the [`Hyphenated`], returning the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let hyphenated = Uuid::nil().hyphenated(); + /// assert_eq!(hyphenated.into_uuid(), Uuid::nil()); + /// ``` + pub const fn into_uuid(self) -> Uuid { + self.0 + } +} + +impl Braced { + /// The length of a braced [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 38; + + /// Creates a [`Braced`] from a [`Uuid`]. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`Braced`]: struct.Braced.html + pub const fn from_uuid(uuid: Uuid) -> Self { + Braced(uuid) + } + + /// Writes the [`Uuid`] as a lower-case hyphenated string surrounded by + /// braces to `buffer`, and returns the subslice of the buffer that contains + /// the encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.braced() + /// .encode_lower(&mut Uuid::encode_buffer()), + /// "{936da01f-9abd-4d9d-80c7-02af85c822a8}" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 40]; + /// uuid.braced().encode_lower(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"{936da01f-9abd-4d9d-80c7-02af85c822a8}!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_braced(self.0.as_bytes(), buffer, false) + } + + /// Writes the [`Uuid`] as an upper-case hyphenated string surrounded by + /// braces to `buffer`, and returns the subslice of the buffer that contains + /// the encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.braced() + /// .encode_upper(&mut Uuid::encode_buffer()), + /// "{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 40]; + /// uuid.braced().encode_upper(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_braced(self.0.as_bytes(), buffer, true) + } + + /// Get a reference to the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let braced = Uuid::nil().braced(); + /// assert_eq!(*braced.as_uuid(), Uuid::nil()); + /// ``` + pub const fn as_uuid(&self) -> &Uuid { + &self.0 + } + + /// Consumes the [`Braced`], returning the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let braced = Uuid::nil().braced(); + /// assert_eq!(braced.into_uuid(), Uuid::nil()); + /// ``` + pub const fn into_uuid(self) -> Uuid { + self.0 + } +} + +impl Simple { + /// The length of a simple [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 32; + + /// Creates a [`Simple`] from a [`Uuid`]. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`Simple`]: struct.Simple.html + pub const fn from_uuid(uuid: Uuid) -> Self { + Simple(uuid) + } + + /// Writes the [`Uuid`] as a lower-case simple string to `buffer`, + /// and returns the subslice of the buffer that contains the encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.simple().encode_lower(&mut Uuid::encode_buffer()), + /// "936da01f9abd4d9d80c702af85c822a8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 36]; + /// assert_eq!( + /// uuid.simple().encode_lower(&mut buf), + /// "936da01f9abd4d9d80c702af85c822a8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_simple(self.0.as_bytes(), buffer, false) + } + + /// Writes the [`Uuid`] as an upper-case simple string to `buffer`, + /// and returns the subslice of the buffer that contains the encoded UUID. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.simple().encode_upper(&mut Uuid::encode_buffer()), + /// "936DA01F9ABD4D9D80C702AF85C822A8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 36]; + /// assert_eq!( + /// uuid.simple().encode_upper(&mut buf), + /// "936DA01F9ABD4D9D80C702AF85C822A8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_simple(self.0.as_bytes(), buffer, true) + } + + /// Get a reference to the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let simple = Uuid::nil().simple(); + /// assert_eq!(*simple.as_uuid(), Uuid::nil()); + /// ``` + pub const fn as_uuid(&self) -> &Uuid { + &self.0 + } + + /// Consumes the [`Simple`], returning the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let simple = Uuid::nil().simple(); + /// assert_eq!(simple.into_uuid(), Uuid::nil()); + /// ``` + pub const fn into_uuid(self) -> Uuid { + self.0 + } +} + +impl Urn { + /// The length of a URN [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 45; + + /// Creates a [`Urn`] from a [`Uuid`]. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`Urn`]: struct.Urn.html + pub const fn from_uuid(uuid: Uuid) -> Self { + Urn(uuid) + } + + /// Writes the [`Uuid`] as a lower-case URN string to + /// `buffer`, and returns the subslice of the buffer that contains the + /// encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.urn().encode_lower(&mut Uuid::encode_buffer()), + /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 49]; + /// uuid.urn().encode_lower(&mut buf); + /// assert_eq!( + /// uuid.urn().encode_lower(&mut buf), + /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_urn(self.0.as_bytes(), buffer, false) + } + + /// Writes the [`Uuid`] as an upper-case URN string to + /// `buffer`, and returns the subslice of the buffer that contains the + /// encoded UUID. + /// + /// This is slightly more efficient than using the formatting + /// infrastructure as it avoids virtual calls, and may avoid + /// double buffering. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// + /// # Panics + /// + /// Panics if the buffer is not large enough: it must have length at least + /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a + /// sufficiently-large temporary buffer. + /// + /// [`LENGTH`]: #associatedconstant.LENGTH + /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// fn main() -> Result<(), uuid::Error> { + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.urn().encode_upper(&mut Uuid::encode_buffer()), + /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8" + /// ); + /// + /// // the buffer is mutated directly, and trailing contents remains + /// let mut buf = [b'!'; 49]; + /// assert_eq!( + /// uuid.urn().encode_upper(&mut buf), + /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] + /// ); + /// + /// Ok(()) + /// } + /// ``` + /// */ + #[inline] + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode_urn(self.0.as_bytes(), buffer, true) + } + + /// Get a reference to the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let urn = Uuid::nil().urn(); + /// assert_eq!(*urn.as_uuid(), Uuid::nil()); + /// ``` + pub const fn as_uuid(&self) -> &Uuid { + &self.0 + } + + /// Consumes the [`Urn`], returning the underlying [`Uuid`]. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let urn = Uuid::nil().urn(); + /// assert_eq!(urn.into_uuid(), Uuid::nil()); + /// ``` + pub const fn into_uuid(self) -> Uuid { + self.0 + } +} + +macro_rules! impl_fmt_traits { + ($($T:ident<$($a:lifetime),*>),+) => {$( + impl<$($a),*> fmt::Display for $T<$($a),*> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } + } + + impl<$($a),*> fmt::LowerHex for $T<$($a),*> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.encode_lower(&mut [0; Self::LENGTH])) + } + } + + impl<$($a),*> fmt::UpperHex for $T<$($a),*> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.encode_upper(&mut [0; Self::LENGTH])) + } + } + + impl_fmt_from!($T<$($a),*>); + )+} +} + +macro_rules! impl_fmt_from { + ($T:ident<>) => { + impl From<Uuid> for $T { + #[inline] + fn from(f: Uuid) -> Self { + $T(f) + } + } + + impl From<$T> for Uuid { + #[inline] + fn from(f: $T) -> Self { + f.into_uuid() + } + } + + impl AsRef<Uuid> for $T { + #[inline] + fn as_ref(&self) -> &Uuid { + &self.0 + } + } + + impl Borrow<Uuid> for $T { + #[inline] + fn borrow(&self) -> &Uuid { + &self.0 + } + } + }; + ($T:ident<$a:lifetime>) => { + impl<$a> From<&$a Uuid> for $T<$a> { + #[inline] + fn from(f: &$a Uuid) -> Self { + $T::from_uuid_ref(f) + } + } + + impl<$a> From<$T<$a>> for &$a Uuid { + #[inline] + fn from(f: $T<$a>) -> &$a Uuid { + f.0 + } + } + + impl<$a> AsRef<Uuid> for $T<$a> { + #[inline] + fn as_ref(&self) -> &Uuid { + self.0 + } + } + + impl<$a> Borrow<Uuid> for $T<$a> { + #[inline] + fn borrow(&self) -> &Uuid { + self.0 + } + } + }; +} + +impl_fmt_traits! { + Hyphenated<>, + Simple<>, + Urn<>, + Braced<> +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hyphenated_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().hyphenated().encode_lower(&mut buf).len(); + assert_eq!(len, super::Hyphenated::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn hyphenated_ref_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().as_hyphenated().encode_lower(&mut buf).len(); + assert_eq!(len, super::Hyphenated::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn simple_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().simple().encode_lower(&mut buf).len(); + assert_eq!(len, super::Simple::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn simple_ref_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().as_simple().encode_lower(&mut buf).len(); + assert_eq!(len, super::Simple::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn urn_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().urn().encode_lower(&mut buf).len(); + assert_eq!(len, super::Urn::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn urn_ref_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().as_urn().encode_lower(&mut buf).len(); + assert_eq!(len, super::Urn::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn braced_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().braced().encode_lower(&mut buf).len(); + assert_eq!(len, super::Braced::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn braced_ref_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().as_braced().encode_lower(&mut buf).len(); + assert_eq!(len, super::Braced::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + #[should_panic] + fn hyphenated_too_small() { + Uuid::nil().hyphenated().encode_lower(&mut [0; 35]); + } + + #[test] + #[should_panic] + fn simple_too_small() { + Uuid::nil().simple().encode_lower(&mut [0; 31]); + } + + #[test] + #[should_panic] + fn urn_too_small() { + Uuid::nil().urn().encode_lower(&mut [0; 44]); + } + + #[test] + #[should_panic] + fn braced_too_small() { + Uuid::nil().braced().encode_lower(&mut [0; 37]); + } + + #[test] + fn hyphenated_to_inner() { + let hyphenated = Uuid::nil().hyphenated(); + assert_eq!(Uuid::from(hyphenated), Uuid::nil()); + } + + #[test] + fn simple_to_inner() { + let simple = Uuid::nil().simple(); + assert_eq!(Uuid::from(simple), Uuid::nil()); + } + + #[test] + fn urn_to_inner() { + let urn = Uuid::nil().urn(); + assert_eq!(Uuid::from(urn), Uuid::nil()); + } + + #[test] + fn braced_to_inner() { + let braced = Uuid::nil().braced(); + assert_eq!(Uuid::from(braced), Uuid::nil()); + } +} |