From 20e253a12418feef08b2a5d96fa3bdd70e14ce6a Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 12:08:17 +1000 Subject: [PATCH 1/8] make ctors that accept slices infallible using arrays --- Cargo.toml | 45 ++++---- src/builder/mod.rs | 259 +++++++++++++++++++++++++++--------------- src/error.rs | 2 - src/lib.rs | 12 +- src/parser/mod.rs | 13 --- src/v1.rs | 50 ++++---- src/winapi_support.rs | 4 +- 7 files changed, 220 insertions(+), 165 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e460b48ea..db235df7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,34 +51,56 @@ status = "actively-developed" [badges.travis-ci] repository = "uuid-rs/uuid" +[features] +default = ["std"] +guid = ["winapi"] +std = [] +stdweb = ["getrandom", "getrandom/js"] +v1 = ["atomic"] +v3 = ["md-5"] +v4 = ["getrandom"] +v5 = ["sha-1"] +wasm-bindgen = ["getrandom", "getrandom/js"] + +# Private [dependencies.getrandom] optional = true version = "0.2" +# Private [dependencies.atomic] default-features = false optional = true version = "0.5" +# Private [dependencies.md-5] default-features = false optional = true version = "0.9" -[dependencies.serde] +# Private +[dependencies.sha-1] default-features = false optional = true -version = "1.0.56" +version = "0.9" -[dependencies.sha-1] +# Public: Used in trait impls on `Uuid` +[dependencies.serde] default-features = false optional = true -version = "0.9" +version = "1.0.56" +# Public: Used in trait impls on `Uuid` [dependencies.slog] optional = true version = "2" +# Public: Used in `From` impls on `Uuid` +[target.'cfg(windows)'.dependencies.winapi] +optional = true +version = "0.3" + [dev-dependencies.bincode] version = "1.0" @@ -97,18 +119,3 @@ version = "0.2" [dev-dependencies.wasm-bindgen-test] version = "0.3" - -[features] -default = ["std"] -guid = ["winapi"] -std = [] -stdweb = ["getrandom", "getrandom/js"] -v1 = ["atomic"] -v3 = ["md-5"] -v4 = ["getrandom"] -v5 = ["sha-1"] -wasm-bindgen = ["getrandom", "getrandom/js"] - -[target.'cfg(windows)'.dependencies.winapi] -optional = true -version = "0.3" diff --git a/src/builder/mod.rs b/src/builder/mod.rs index ad6a6b805..5b414f905 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -46,10 +46,6 @@ impl Uuid { /// Creates a UUID from four field values. /// - /// # Errors - /// - /// This function will return an error if `d4`'s length is not 8 bytes. - /// /// # Examples /// /// Basic usage: @@ -57,31 +53,25 @@ impl Uuid { /// ``` /// use uuid::Uuid; /// + /// let d1 = 0xAB3F1097u32; + /// let d2 = 0x501Eu16; + /// let d3 = 0xB736u16; /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// - /// let uuid = Uuid::from_fields(42, 12, 5, &d4); - /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); - /// - /// let expected_uuid = - /// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); + /// let uuid = Uuid::from_fields(d1, d2, d3, &d4); /// - /// assert_eq!(expected_uuid, uuid); + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "ab3f1097-501e-b736-0c03-0938362b0809" + /// ); /// ``` - pub fn from_fields( + pub const fn from_fields( d1: u32, d2: u16, d3: u16, - d4: &[u8], - ) -> Result { - const D4_LEN: usize = 8; - - let len = d4.len(); - - if len != D4_LEN { - return crate::err(Error::new(D4_LEN, len)); - } - - Ok(Uuid::from_bytes([ + d4: &[u8; 8], + ) -> Uuid { + Uuid::from_bytes([ (d1 >> 24) as u8, (d1 >> 16) as u8, (d1 >> 8) as u8, @@ -98,7 +88,7 @@ impl Uuid { d4[5], d4[6], d4[7], - ])) + ]) } /// Creates a UUID from four field values in little-endian order. @@ -119,28 +109,19 @@ impl Uuid { /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// /// let uuid = Uuid::from_fields_le(d1, d2, d3, &d4); - /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); /// - /// let expected_uuid = - /// Ok(String::from("97103fab-1e50-36b7-0c03-0938362b0809")); - /// - /// assert_eq!(expected_uuid, uuid); + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "97103fab-1e50-36b7-0c03-0938362b0809" + /// ); /// ``` - pub fn from_fields_le( + pub const fn from_fields_le( d1: u32, d2: u16, d3: u16, d4: &[u8], - ) -> Result { - const D4_LEN: usize = 8; - - let len = d4.len(); - - if len != D4_LEN { - return crate::err(Error::new(D4_LEN, len)); - } - - Ok(Uuid::from_bytes([ + ) -> Uuid { + Uuid::from_bytes([ d1 as u8, (d1 >> 8) as u8, (d1 >> 16) as u8, @@ -157,10 +138,27 @@ impl Uuid { d4[5], d4[6], d4[7], - ])) + ]) } /// Creates a UUID from a 128bit value. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let v = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8u128; + /// + /// let uuid = Uuid::from_u128(v); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" + /// ); + /// ``` pub const fn from_u128(v: u128) -> Self { Uuid::from_bytes([ (v >> 120) as u8, @@ -188,6 +186,23 @@ impl Uuid { /// This is based on the endianness of the UUID, rather than the target /// environment so bytes will be flipped on both big and little endian /// machines. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let v = 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1u128; + /// + /// let uuid = Uuid::from_u128_le(v); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" + /// ); + /// ``` pub const fn from_u128_le(v: u128) -> Self { Uuid::from_bytes([ v as u8, @@ -210,6 +225,24 @@ impl Uuid { } /// Creates a UUID from two 64bit values. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let hi = 0xa1a2a3a4b1b2c1c2u64; + /// let lo = 0xd1d2d3d4d5d6d7d8u64; + /// + /// let uuid = Uuid::from_u64_pair(hi, lo); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" + /// ); + /// ``` pub const fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self { Uuid::from_bytes([ (high_bits >> 56) as u8, @@ -242,22 +275,25 @@ impl Uuid { /// Basic usage: /// /// ``` + /// # fn main() -> Result<(), Box> { /// use uuid::Uuid; /// /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87]; /// - /// let uuid = Uuid::from_slice(&bytes); - /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); - /// - /// let expected_uuid = - /// Ok(String::from("0436430c-2b02-624c-2032-570501212b57")); + /// let uuid = Uuid::from_slice(&bytes)?; /// - /// assert_eq!(expected_uuid, uuid); + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "0436430c-2b02-624c-2032-570501212b57" + /// ); + /// # Ok(()) + /// # } /// ``` /// /// An incorrect number of bytes: /// /// ``` + /// # fn main() -> Result<(), Box> { /// use uuid::Uuid; /// /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76]; @@ -265,6 +301,8 @@ impl Uuid { /// let uuid = Uuid::from_slice(&bytes); /// /// assert!(uuid.is_err()); + /// # Ok(()) + /// # } /// ``` pub fn from_slice(b: &[u8]) -> Result { const BYTES_LEN: usize = 16; @@ -281,32 +319,32 @@ impl Uuid { } /// Creates a UUID using the supplied bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// use uuid::Uuid; + /// + /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87]; + /// + /// let uuid = Uuid::from_bytes(bytes); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "0436430c-2b02-624c-2032-570501212b57" + /// ); + /// # Ok(()) + /// # } + /// ``` pub const fn from_bytes(bytes: Bytes) -> Uuid { Uuid(bytes) } } -/// A builder struct for creating a UUID. -/// -/// # Examples -/// -/// Creating a v4 UUID from externally generated bytes: -/// -/// ``` -/// use uuid::{Builder, Variant, Version}; -/// -/// # let rng = || [ -/// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, -/// # 145, 63, 62, -/// # ]; -/// let random_bytes = rng(); -/// let uuid = Builder::from_bytes(random_bytes) -/// .set_variant(Variant::RFC4122) -/// .set_version(Version::Random) -/// .build(); -/// ``` - -impl crate::Builder { +impl Builder { /// Creates a `Builder` using the supplied bytes. /// /// # Examples @@ -385,52 +423,63 @@ impl crate::Builder { /// Creates a `Builder` from four field values. /// - /// # Errors - /// - /// This function will return an error if `d4`'s length is not 8 bytes. - /// /// # Examples /// /// Basic usage: /// /// ``` + /// let d1 = 0xAB3F1097u32; + /// let d2 = 0x501Eu16; + /// let d3 = 0xB736u16; /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// - /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4); - /// let uuid = - /// builder.map(|mut builder| builder.build().to_hyphenated().to_string()); + /// let uuid = uuid::Builder::from_fields(d1, d2, d3, &d4).into_uuid(); /// - /// let expected_uuid = - /// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); - /// - /// assert_eq!(expected_uuid, uuid); + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "ab3f1097-501e-b736-0c03-0938362b0809" + /// ); /// ``` + pub const fn from_fields( + d1: u32, + d2: u16, + d3: u16, + d4: &[u8; 8], + ) -> Self { + Builder::from_bytes(*Uuid::from_fields(d1, d2, d3, d4).as_bytes()) + } + + /// Creates a `Builder` from four field values. /// - /// An invalid length: + /// # Examples + /// + /// Basic usage: /// /// ``` - /// let d4 = [12]; + /// let d1 = 0xAB3F1097u32; + /// let d2 = 0x501Eu16; + /// let d3 = 0xB736u16; + /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// - /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4); + /// let uuid = uuid::Builder::from_fields_le(d1, d2, d3, &d4).into_uuid(); /// - /// assert!(builder.is_err()); + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "97103fab-1e50-36b7-0c03-0938362b0809" + /// ); /// ``` - pub fn from_fields( + pub const fn from_fields_le( d1: u32, d2: u16, d3: u16, - d4: &[u8], - ) -> Result { - Uuid::from_fields(d1, d2, d3, d4).map(|uuid| { - let bytes = *uuid.as_bytes(); - - crate::Builder::from_bytes(bytes) - }) + d4: &[u8; 8], + ) -> Self { + Builder::from_bytes(*Uuid::from_fields_le(d1, d2, d3, d4).as_bytes()) } /// Creates a `Builder` from a 128bit value. - pub fn from_u128(v: u128) -> Self { - crate::Builder::from_bytes(*Uuid::from_u128(v).as_bytes()) + pub const fn from_u128(v: u128) -> Self { + Builder::from_bytes(*Uuid::from_u128(v).as_bytes()) } /// Creates a `Builder` with an initial [`Uuid::nil`]. @@ -467,6 +516,20 @@ impl crate::Builder { self } + /// Specifies the variant of the UUID. + pub const fn with_variant(mut self, v: crate::Variant) -> Self { + let byte = self.0[8]; + + self.0[8] = match v { + crate::Variant::NCS => byte & 0x7f, + crate::Variant::RFC4122 => (byte & 0x3f) | 0x80, + crate::Variant::Microsoft => (byte & 0x1f) | 0xc0, + crate::Variant::Future => (byte & 0x1f) | 0xe0, + }; + + self + } + /// Specifies the version number of the UUID. pub fn set_version(&mut self, v: crate::Version) -> &mut Self { self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); @@ -474,6 +537,13 @@ impl crate::Builder { self } + /// Specifies the version number of the UUID. + pub const fn with_version(mut self, v: crate::Version) -> Self { + self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); + + self + } + /// Hands over the internal constructed [`Uuid`]. /// /// # Examples @@ -495,4 +565,9 @@ impl crate::Builder { pub fn build(&mut self) -> Uuid { Uuid::from_bytes(self.0) } + + /// Convert the builder into a [`Uuid`]. + pub const fn into_uuid(self) -> Uuid { + Uuid::from_bytes(self.0) + } } diff --git a/src/error.rs b/src/error.rs index b48ed7900..e3f4d3695 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,8 +11,6 @@ pub(crate) fn err(err: impl Into) -> Result { Err(err.into()) } -// TODO: write tests for Error -// BODY: not immediately blocking, but should be covered for 1.0 #[derive(Clone, Debug, Eq, Hash, PartialEq)] enum Inner { /// An error occurred while handling [`Uuid`] bytes. diff --git a/src/lib.rs b/src/lib.rs index 5c3b1e928..e087649d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,7 +209,7 @@ mod v5; mod winapi_support; use crate::{ - error::err, + error::*, std::{convert, fmt, str}, }; @@ -953,7 +953,7 @@ mod tests { let d3: u16 = 0xc1c2; let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; - let u = Uuid::from_fields(d1, d2, d3, &d4).unwrap(); + let u = Uuid::from_fields(d1, d2, d3, &d4); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.to_simple().to_string(); @@ -968,7 +968,7 @@ mod tests { let d3: u16 = 0xc2c1; let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; - let u = Uuid::from_fields_le(d1, d2, d3, &d4).unwrap(); + let u = Uuid::from_fields_le(d1, d2, d3, &d4); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.to_simple().to_string(); @@ -996,7 +996,7 @@ mod tests { let d3_in: u16 = 0xc1c2; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; - let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in).unwrap(); + let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.as_fields(); assert_eq!(d1_in, d1_out); @@ -1013,7 +1013,7 @@ mod tests { let d3_in: u16 = 0xc2c1; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; - let u = Uuid::from_fields_le(d1_in, d2_in, d3_in, d4_in).unwrap(); + let u = Uuid::from_fields_le(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le(); assert_eq!(d1_in, d1_out); @@ -1030,7 +1030,7 @@ mod tests { let d3_in: u16 = 0xc1c2; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; - let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in).unwrap(); + let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le(); assert_eq!(d1_in, d1_out.swap_bytes()); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9cc518a13..0dd08a75f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -29,19 +29,6 @@ fn len_matches_any(len: usize, crits: &[usize]) -> bool { false } -/// Check if the length matches any criteria lengths in the given range -/// (inclusive). -#[allow(dead_code)] -fn len_matches_range(len: usize, min: usize, max: usize) -> bool { - for crit in min..=max { - if len == crit { - return true; - } - } - - false -} - // Accumulated length of each hyphenated group in hex digits. const ACC_GROUP_LENS: [usize; 5] = [8, 12, 16, 20, 32]; diff --git a/src/v1.rs b/src/v1.rs index 7ec1e8e13..e7674c542 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -164,7 +164,7 @@ impl Uuid { /// /// let context = Context::new(42); /// let ts = Timestamp::from_unix(&context, 1497624119, 1234); - /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); + /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.to_hyphenated().to_string(), @@ -191,14 +191,7 @@ impl Uuid { /// [`Timestamp`]: v1/struct.Timestamp.html /// [`ClockSequence`]: v1/struct.ClockSequence.html /// [`Context`]: v1/struct.Context.html - pub fn new_v1(ts: Timestamp, node_id: &[u8]) -> Result { - const NODE_ID_LEN: usize = 6; - - let len = node_id.len(); - if len != NODE_ID_LEN { - return crate::err(crate::builder::Error::new(NODE_ID_LEN, len)); - } - + pub fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self { let time_low = (ts.ticks & 0xFFFF_FFFF) as u32; let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16; let time_high_and_version = @@ -229,28 +222,25 @@ impl Uuid { /// value into more commonly-used formats, such as a unix timestamp. /// /// [`Timestamp`]: v1/struct.Timestamp.html - pub fn to_timestamp(&self) -> Option { - if self - .get_version() - .map(|v| v != Version::Mac) - .unwrap_or(true) - { - return None; + pub const fn to_timestamp(&self) -> Option { + match self.get_version() { + Some(Version::Mac) => { + let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56 + | ((self.as_bytes()[7]) as u64) << 48 + | ((self.as_bytes()[4]) as u64) << 40 + | ((self.as_bytes()[5]) as u64) << 32 + | ((self.as_bytes()[0]) as u64) << 24 + | ((self.as_bytes()[1]) as u64) << 16 + | ((self.as_bytes()[2]) as u64) << 8 + | (self.as_bytes()[3] as u64); + + let counter: u16 = ((self.as_bytes()[8] & 0x3F) as u16) << 8 + | (self.as_bytes()[9] as u16); + + Some(Timestamp::from_rfc4122(ticks, counter)) + }, + _ => None } - - let ticks: u64 = u64::from(self.as_bytes()[6] & 0x0F) << 56 - | u64::from(self.as_bytes()[7]) << 48 - | u64::from(self.as_bytes()[4]) << 40 - | u64::from(self.as_bytes()[5]) << 32 - | u64::from(self.as_bytes()[0]) << 24 - | u64::from(self.as_bytes()[1]) << 16 - | u64::from(self.as_bytes()[2]) << 8 - | u64::from(self.as_bytes()[3]); - - let counter: u16 = u16::from(self.as_bytes()[8] & 0x3F) << 8 - | u16::from(self.as_bytes()[9]); - - Some(Timestamp::from_rfc4122(ticks, counter)) } } diff --git a/src/winapi_support.rs b/src/winapi_support.rs index 69e886ed7..417669f9d 100644 --- a/src/winapi_support.rs +++ b/src/winapi_support.rs @@ -6,15 +6,13 @@ impl Uuid { /// Converts a little endian winapi `GUID` into a [`Uuid`] /// /// [`Uuid`]: ../struct.Uuid.html - pub fn from_guid(guid: guiddef::GUID) -> Self { + pub const fn from_guid(guid: guiddef::GUID) -> Self { Uuid::from_fields_le( guid.Data1 as u32, guid.Data2 as u16, guid.Data3 as u16, &(guid.Data4 as [u8; 8]), ) - .unwrap() // Note: The result in this particular instance is always Ok, - // so we can safely unwrap. } /// Converts a [`Uuid`] into a little endian winapi `GUID` From 7748a37f137139128c2f05b841c7a7390437e3bd Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 17:33:43 +1000 Subject: [PATCH 2/8] fix up v1 --- src/v1.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index e7674c542..07a2a9948 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -180,7 +180,7 @@ impl Uuid { /// /// let context = Context::new(42); /// let ts = Timestamp::from_rfc4122(1497624119, 0); - /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); + /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.to_hyphenated().to_string(), @@ -191,7 +191,7 @@ impl Uuid { /// [`Timestamp`]: v1/struct.Timestamp.html /// [`ClockSequence`]: v1/struct.ClockSequence.html /// [`Context`]: v1/struct.Context.html - pub fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self { + pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self { let time_low = (ts.ticks & 0xFFFF_FFFF) as u32; let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16; let time_high_and_version = @@ -199,12 +199,14 @@ impl Uuid { let mut d4 = [0; 8]; - { - d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80; - d4[1] = (ts.counter & 0xFF) as u8; - } - - d4[2..].copy_from_slice(node_id); + d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80; + d4[1] = (ts.counter & 0xFF) as u8; + d4[2] = node_id[0]; + d4[3] = node_id[1]; + d4[4] = node_id[2]; + d4[5] = node_id[3]; + d4[6] = node_id[4]; + d4[7] = node_id[5]; Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4) } @@ -287,8 +289,7 @@ mod tests { let uuid = Uuid::new_v1( Timestamp::from_unix(&context, time, time_fraction), &node, - ) - .unwrap(); + ); assert_eq!(uuid.get_version(), Some(Version::Mac)); assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); @@ -307,8 +308,7 @@ mod tests { let uuid2 = Uuid::new_v1( Timestamp::from_unix(&context, time, time_fraction), &node, - ) - .unwrap(); + ); assert_eq!( uuid2.to_hyphenated().to_string(), From 63170f8d9cf49b9ed4d5212902099f1b510ca119 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 17:45:42 +1000 Subject: [PATCH 3/8] make get_variant infallible --- src/lib.rs | 29 +++++++++++++++++------------ src/v1.rs | 2 +- src/v3.rs | 4 ++-- src/v4.rs | 2 +- src/v5.rs | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e087649d9..5ecac7ec0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -305,15 +305,20 @@ impl Uuid { /// /// This determines the interpretation of the structure of the UUID. /// Currently only the RFC4122 variant is generated by this module. + /// Callers should only trust the value returned by this method if they + /// trust the UUID itself. /// /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1) - pub const fn get_variant(&self) -> Option { + pub const fn get_variant(&self) -> Variant { match self.as_bytes()[8] { - x if x & 0x80 == 0x00 => Some(Variant::NCS), - x if x & 0xc0 == 0x80 => Some(Variant::RFC4122), - x if x & 0xe0 == 0xc0 => Some(Variant::Microsoft), - x if x & 0xe0 == 0xe0 => Some(Variant::Future), - _ => None, + x if x & 0x80 == 0x00 => Variant::NCS, + x if x & 0xc0 == 0x80 => Variant::RFC4122, + x if x & 0xe0 == 0xc0 => Variant::Microsoft, + x if x & 0xe0 == 0xe0 => Variant::Future, + // The above match arms are actually exhaustive + // We just return `Future` here because we can't + // use `unreachable!()` in a `const fn` + _ => Variant::Future, } } @@ -845,12 +850,12 @@ mod tests { let uuid6 = Uuid::parse_str("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap(); - assert_eq!(uuid1.get_variant().unwrap(), Variant::RFC4122); - assert_eq!(uuid2.get_variant().unwrap(), Variant::RFC4122); - assert_eq!(uuid3.get_variant().unwrap(), Variant::RFC4122); - assert_eq!(uuid4.get_variant().unwrap(), Variant::Microsoft); - assert_eq!(uuid5.get_variant().unwrap(), Variant::Microsoft); - assert_eq!(uuid6.get_variant().unwrap(), Variant::NCS); + assert_eq!(uuid1.get_variant(), Variant::RFC4122); + assert_eq!(uuid2.get_variant(), Variant::RFC4122); + assert_eq!(uuid3.get_variant(), Variant::RFC4122); + assert_eq!(uuid4.get_variant(), Variant::Microsoft); + assert_eq!(uuid5.get_variant(), Variant::Microsoft); + assert_eq!(uuid6.get_variant(), Variant::NCS); } #[test] diff --git a/src/v1.rs b/src/v1.rs index 07a2a9948..9a4694153 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -292,7 +292,7 @@ mod tests { ); assert_eq!(uuid.get_version(), Some(Version::Mac)); - assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!( uuid.to_hyphenated().to_string(), "20616934-4ba2-11e7-8000-010203040506" diff --git a/src/v3.rs b/src/v3.rs index ca44d3ad8..af85d93c0 100644 --- a/src/v3.rs +++ b/src/v3.rs @@ -136,8 +136,8 @@ mod tests { fn test_new() { for &(ref ns, ref name, _) in FIXTURE { let uuid = Uuid::new_v3(*ns, name.as_bytes()); - assert_eq!(uuid.get_version().unwrap(), Version::Md5); - assert_eq!(uuid.get_variant().unwrap(), Variant::RFC4122); + assert_eq!(uuid.get_version(), Some(Version::Md5)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); } } diff --git a/src/v4.rs b/src/v4.rs index dcd7c8fc6..f74bff87f 100644 --- a/src/v4.rs +++ b/src/v4.rs @@ -51,7 +51,7 @@ mod tests { let uuid = Uuid::new_v4(); assert_eq!(uuid.get_version(), Some(Version::Random)); - assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); } #[test] diff --git a/src/v5.rs b/src/v5.rs index c4816ba8a..26bf3fab2 100644 --- a/src/v5.rs +++ b/src/v5.rs @@ -156,8 +156,8 @@ mod tests { for &(ref ns, ref name, ref u) in FIXTURE { let uuid = Uuid::new_v5(*ns, name.as_bytes()); - assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); assert_eq!(uuid.get_version(), Some(Version::Sha1)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!(Ok(uuid), u.parse()); } } From ce3eca7c9562df7a2585f26996df6c6ba8e552c5 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 21:13:28 +1000 Subject: [PATCH 4/8] serialize Uuid as [u8; 16] instead of &[u8] --- src/adapter/compact.rs | 80 ------------------------------------------ src/adapter/mod.rs | 3 -- src/serde_support.rs | 47 +++++++++++++------------ 3 files changed, 24 insertions(+), 106 deletions(-) delete mode 100644 src/adapter/compact.rs diff --git a/src/adapter/compact.rs b/src/adapter/compact.rs deleted file mode 100644 index 7a28c4614..000000000 --- a/src/adapter/compact.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Module for use with `#[serde(with = "...")]` to serialize a [`Uuid`] -//! as a `[u8; 16]`. -//! -//! [`Uuid`]: ../../struct.Uuid.html - -/// Serializer for a [`Uuid`] into a `[u8; 16]` -/// -/// [`Uuid`]: ../../struct.Uuid.html -pub fn serialize(u: &crate::Uuid, serializer: S) -> Result -where - S: serde::Serializer, -{ - serde::Serialize::serialize(u.as_bytes(), serializer) -} - -/// Deserializer from a `[u8; 16]` into a [`Uuid`] -/// -/// [`Uuid`]: ../../struct.Uuid.html -pub fn deserialize<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - let bytes: [u8; 16] = serde::Deserialize::deserialize(deserializer)?; - - Ok(crate::Uuid::from_bytes(bytes)) -} - -#[cfg(test)] -mod tests { - use serde_test; - - #[test] - fn test_serialize_compact() { - #[derive( - serde_derive::Serialize, Debug, serde_derive::Deserialize, PartialEq, - )] - struct UuidContainer { - #[serde(with = "super")] - u: crate::Uuid, - } - use serde_test::Configure; - - let uuid_bytes = b"F9168C5E-CEB2-4F"; - let container = UuidContainer { - u: crate::Uuid::from_slice(uuid_bytes).unwrap(), - }; - - // more complex because of the struct wrapping the actual UUID - // serialization - serde_test::assert_tokens( - &container.compact(), - &[ - serde_test::Token::Struct { - name: "UuidContainer", - len: 1, - }, - serde_test::Token::Str("u"), - serde_test::Token::Tuple { len: 16 }, - serde_test::Token::U8(uuid_bytes[0]), - serde_test::Token::U8(uuid_bytes[1]), - serde_test::Token::U8(uuid_bytes[2]), - serde_test::Token::U8(uuid_bytes[3]), - serde_test::Token::U8(uuid_bytes[4]), - serde_test::Token::U8(uuid_bytes[5]), - serde_test::Token::U8(uuid_bytes[6]), - serde_test::Token::U8(uuid_bytes[7]), - serde_test::Token::U8(uuid_bytes[8]), - serde_test::Token::U8(uuid_bytes[9]), - serde_test::Token::U8(uuid_bytes[10]), - serde_test::Token::U8(uuid_bytes[11]), - serde_test::Token::U8(uuid_bytes[12]), - serde_test::Token::U8(uuid_bytes[13]), - serde_test::Token::U8(uuid_bytes[14]), - serde_test::Token::U8(uuid_bytes[15]), - serde_test::Token::TupleEnd, - serde_test::Token::StructEnd, - ], - ) - } -} diff --git a/src/adapter/mod.rs b/src/adapter/mod.rs index 2cb682e37..3dcaf43a8 100644 --- a/src/adapter/mod.rs +++ b/src/adapter/mod.rs @@ -14,9 +14,6 @@ use crate::prelude::*; use crate::std::{borrow::Borrow, fmt, str}; -#[cfg(feature = "serde")] -pub mod compact; - /// An adaptor for formatting an [`Uuid`] as a hyphenated string. /// /// Takes an owned instance of the [`Uuid`]. diff --git a/src/serde_support.rs b/src/serde_support.rs index b4a3ae086..8c5d687b6 100644 --- a/src/serde_support.rs +++ b/src/serde_support.rs @@ -22,7 +22,7 @@ impl Serialize for Uuid { serializer .serialize_str(self.to_hyphenated().encode_lower(&mut [0; 36])) } else { - serializer.serialize_bytes(self.as_bytes()) + self.as_bytes().serialize(serializer) } } } @@ -65,27 +65,9 @@ impl<'de> Deserialize<'de> for Uuid { deserializer.deserialize_str(UuidStringVisitor) } else { - struct UuidBytesVisitor; + let bytes: [u8; 16] = Deserialize::deserialize(deserializer)?; - impl<'vi> de::Visitor<'vi> for UuidBytesVisitor { - type Value = Uuid; - - fn expecting( - &self, - formatter: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(formatter, "bytes") - } - - fn visit_bytes( - self, - value: &[u8], - ) -> Result { - Uuid::from_slice(value).map_err(de_error) - } - } - - deserializer.deserialize_bytes(UuidBytesVisitor) + Ok(Uuid::from_bytes(bytes)) } } } @@ -107,7 +89,26 @@ mod serde_tests { fn test_serialize_compact() { let uuid_bytes = b"F9168C5E-CEB2-4F"; let u = Uuid::from_slice(uuid_bytes).unwrap(); - serde_test::assert_tokens(&u.compact(), &[Token::Bytes(uuid_bytes)]); + serde_test::assert_tokens(&u.compact(), &[ + serde_test::Token::Tuple { len: 16 }, + serde_test::Token::U8(uuid_bytes[0]), + serde_test::Token::U8(uuid_bytes[1]), + serde_test::Token::U8(uuid_bytes[2]), + serde_test::Token::U8(uuid_bytes[3]), + serde_test::Token::U8(uuid_bytes[4]), + serde_test::Token::U8(uuid_bytes[5]), + serde_test::Token::U8(uuid_bytes[6]), + serde_test::Token::U8(uuid_bytes[7]), + serde_test::Token::U8(uuid_bytes[8]), + serde_test::Token::U8(uuid_bytes[9]), + serde_test::Token::U8(uuid_bytes[10]), + serde_test::Token::U8(uuid_bytes[11]), + serde_test::Token::U8(uuid_bytes[12]), + serde_test::Token::U8(uuid_bytes[13]), + serde_test::Token::U8(uuid_bytes[14]), + serde_test::Token::U8(uuid_bytes[15]), + serde_test::Token::TupleEnd, + ]); } #[test] @@ -119,7 +120,7 @@ mod serde_tests { serde_test::assert_de_tokens_error::>( &[Token::Bytes(b"hello_world")], - "UUID parsing failed: invalid bytes length: expected 16, found 11", + "invalid type: byte array, expected an array of length 16", ); } } From 9d1484252e59989af9fd39272f63aec180855033 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 21:23:42 +1000 Subject: [PATCH 5/8] rename "adapter" to "fmt" --- src/error.rs | 13 ------- src/{adapter/mod.rs => fmt.rs} | 57 ++++++++++++++++++++++++------ src/lib.rs | 63 +++++----------------------------- src/parser/mod.rs | 30 ++++++++++------ 4 files changed, 75 insertions(+), 88 deletions(-) rename src/{adapter/mod.rs => fmt.rs} (96%) diff --git a/src/error.rs b/src/error.rs index e3f4d3695..d572942d8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,20 +13,7 @@ pub(crate) fn err(err: impl Into) -> Result { #[derive(Clone, Debug, Eq, Hash, PartialEq)] enum Inner { - /// An error occurred while handling [`Uuid`] bytes. - /// - /// See [`BytesError`] - /// - /// [`BytesError`]: struct.BytesError.html - /// [`Uuid`]: struct.Uuid.html Build(builder::Error), - - /// An error occurred while parsing a [`Uuid`] string. - /// - /// See [`parser::ParseError`] - /// - /// [`parser::ParseError`]: parser/enum.ParseError.html - /// [`Uuid`]: struct.Uuid.html Parser(parser::Error), } diff --git a/src/adapter/mod.rs b/src/fmt.rs similarity index 96% rename from src/adapter/mod.rs rename to src/fmt.rs index 3dcaf43a8..850f67fc4 100644 --- a/src/adapter/mod.rs +++ b/src/fmt.rs @@ -14,7 +14,44 @@ use crate::prelude::*; use crate::std::{borrow::Borrow, fmt, str}; -/// An adaptor for formatting an [`Uuid`] as a hyphenated string. +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.to_hyphenated_ref(), f) + } +} + +impl fmt::UpperHex for Uuid { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f) + } +} + +/// An adapter for formatting an [`Uuid`] as a hyphenated string. /// /// Takes an owned instance of the [`Uuid`]. /// @@ -22,7 +59,7 @@ use crate::std::{borrow::Borrow, fmt, str}; #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Hyphenated(Uuid); -/// An adaptor for formatting an [`Uuid`] as a hyphenated string. +/// An adapter for formatting an [`Uuid`] as a hyphenated string. /// /// Takes a reference of the [`Uuid`]. /// @@ -30,7 +67,7 @@ pub struct Hyphenated(Uuid); #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct HyphenatedRef<'a>(&'a Uuid); -/// An adaptor for formatting an [`Uuid`] as a simple string. +/// An adapter for formatting an [`Uuid`] as a simple string. /// /// Takes an owned instance of the [`Uuid`]. /// @@ -38,7 +75,7 @@ pub struct HyphenatedRef<'a>(&'a Uuid); #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Simple(Uuid); -/// An adaptor for formatting an [`Uuid`] as a simple string. +/// An adapter for formatting an [`Uuid`] as a simple string. /// /// Takes a reference of the [`Uuid`]. /// @@ -46,7 +83,7 @@ pub struct Simple(Uuid); #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct SimpleRef<'a>(&'a Uuid); -/// An adaptor for formatting an [`Uuid`] as a URN string. +/// An adapter for formatting an [`Uuid`] as a URN string. /// /// Takes an owned instance of the [`Uuid`]. /// @@ -54,7 +91,7 @@ pub struct SimpleRef<'a>(&'a Uuid); #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Urn(Uuid); -/// An adaptor for formatting an [`Uuid`] as a URN string. +/// An adapter for formatting an [`Uuid`] as a URN string. /// /// Takes a reference of the [`Uuid`]. /// @@ -924,7 +961,7 @@ impl<'a> UrnRef<'a> { } } -macro_rules! impl_adapter_traits { +macro_rules! impl_fmt_traits { ($($T:ident<$($a:lifetime),*>),+) => {$( impl<$($a),*> fmt::Display for $T<$($a),*> { #[inline] @@ -947,11 +984,11 @@ macro_rules! impl_adapter_traits { } } - impl_adapter_from!($T<$($a),*>); + impl_fmt_from!($T<$($a),*>); )+} } -macro_rules! impl_adapter_from { +macro_rules! impl_fmt_from { ($T:ident<>) => { impl From for $T { #[inline] @@ -1012,7 +1049,7 @@ macro_rules! impl_adapter_from { }; } -impl_adapter_traits! { +impl_fmt_traits! { Hyphenated<>, HyphenatedRef<'a>, Simple<>, diff --git a/src/lib.rs b/src/lib.rs index 5ecac7ec0..2e2c650fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,7 +189,7 @@ mod error; mod parser; mod prelude; -pub mod adapter; +pub mod fmt; #[cfg(feature = "v1")] pub mod v1; @@ -210,7 +210,7 @@ mod winapi_support; use crate::{ error::*, - std::{convert, fmt, str}, + std::convert, }; pub use crate::error::Error; @@ -578,7 +578,7 @@ impl Uuid { } /// A buffer that can be used for `encode_...` calls, that is - /// guaranteed to be long enough for any of the adapters. + /// guaranteed to be long enough for any of the format format adapters. /// /// # Examples /// @@ -603,53 +603,8 @@ impl Uuid { /// "urn:uuid:00000000-0000-0000-0000-000000000000" /// ); /// ``` - pub const fn encode_buffer() -> [u8; adapter::Urn::LENGTH] { - [0; adapter::Urn::LENGTH] - } -} - -impl 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.to_hyphenated_ref(), f) - } -} - -impl fmt::UpperHex for Uuid { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f) - } -} - -impl str::FromStr for Uuid { - type Err = Error; - - fn from_str(uuid_str: &str) -> Result { - Uuid::parse_str(uuid_str) + pub const fn encode_buffer() -> [u8; fmt::Urn::LENGTH] { + [0; fmt::Urn::LENGTH] } } @@ -712,7 +667,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_display() { - use super::fmt::Write; + use crate::std::fmt::Write; let uuid = test_util::new(); let s = uuid.to_string(); @@ -728,7 +683,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_lowerhex() { - use super::fmt::Write; + use crate::std::fmt::Write; let mut buffer = String::new(); let uuid = test_util::new(); @@ -759,7 +714,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_to_string() { - use super::fmt::Write; + use crate::std::fmt::Write; let uuid = test_util::new(); let s = uuid.to_string(); @@ -775,7 +730,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_upperhex() { - use super::fmt::Write; + use crate::std::fmt::Write; let mut buffer = String::new(); let uuid = test_util::new(); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0dd08a75f..0ab341fd1 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -16,7 +16,15 @@ pub(crate) mod error; pub(crate) use self::error::Error; -use crate::{adapter, Uuid}; +use crate::{fmt, std::str, Uuid}; + +impl str::FromStr for Uuid { + type Err = crate::Error; + + fn from_str(uuid_str: &str) -> Result { + Uuid::parse_str(uuid_str) + } +} /// Check if the length matches any of the given criteria lengths. fn len_matches_any(len: usize, crits: &[usize]) -> bool { @@ -45,16 +53,16 @@ impl Uuid { // Ensure length is valid for any of the supported formats let len = input.len(); - if len == adapter::Urn::LENGTH && input.starts_with("urn:uuid:") { + if len == fmt::Urn::LENGTH && input.starts_with("urn:uuid:") { input = &input[9..]; } else if !len_matches_any( len, - &[adapter::Hyphenated::LENGTH, adapter::Simple::LENGTH], + &[fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH], ) { return crate::err(Error::InvalidLength { expected: error::ExpectedLength::Any(&[ - adapter::Hyphenated::LENGTH, - adapter::Simple::LENGTH, + fmt::Hyphenated::LENGTH, + fmt::Simple::LENGTH, ]), found: len, }); @@ -67,12 +75,12 @@ impl Uuid { let mut buffer = [0u8; 16]; for (i_char, chr) in input.bytes().enumerate() { - if digit as usize >= adapter::Simple::LENGTH && group != 4 { + if digit as usize >= fmt::Simple::LENGTH && group != 4 { if group == 0 { return crate::err(Error::InvalidLength { expected: error::ExpectedLength::Any(&[ - adapter::Hyphenated::LENGTH, - adapter::Simple::LENGTH, + fmt::Hyphenated::LENGTH, + fmt::Simple::LENGTH, ]), found: len, }); @@ -189,14 +197,14 @@ impl Uuid { #[cfg(test)] mod tests { use super::*; - use crate::{adapter, std::string::ToString, test_util}; + use crate::{fmt, std::string::ToString, test_util}; #[test] fn test_parse_uuid_v4() { const EXPECTED_UUID_LENGTHS: error::ExpectedLength = error::ExpectedLength::Any(&[ - adapter::Hyphenated::LENGTH, - adapter::Simple::LENGTH, + fmt::Hyphenated::LENGTH, + fmt::Simple::LENGTH, ]); const EXPECTED_GROUP_COUNTS: error::ExpectedLength = From 40c4b1670b7b0a6f6f2653cf279a4170853fde77 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 21:46:10 +1000 Subject: [PATCH 6/8] simplify errors and avoid repeating Display and source --- src/{builder/mod.rs => builder.rs} | 60 +++----- src/builder/error.rs | 52 ------- src/error.rs | 155 ++++++++++++++----- src/lib.rs | 5 +- src/{parser/mod.rs => parser.rs} | 240 +++++++++++++---------------- src/parser/error.rs | 149 ------------------ 6 files changed, 238 insertions(+), 423 deletions(-) rename src/{builder/mod.rs => builder.rs} (90%) delete mode 100644 src/builder/error.rs rename src/{parser/mod.rs => parser.rs} (63%) delete mode 100644 src/parser/error.rs diff --git a/src/builder/mod.rs b/src/builder.rs similarity index 90% rename from src/builder/mod.rs rename to src/builder.rs index 5b414f905..c17dd44cd 100644 --- a/src/builder/mod.rs +++ b/src/builder.rs @@ -13,9 +13,7 @@ //! //! [`Uuid`]: ../struct.Uuid.html -mod error; -pub(crate) use self::error::Error; - +use crate::error::*; use crate::prelude::*; impl Uuid { @@ -304,13 +302,12 @@ impl Uuid { /// # Ok(()) /// # } /// ``` - pub fn from_slice(b: &[u8]) -> Result { - const BYTES_LEN: usize = 16; - - let len = b.len(); - - if len != BYTES_LEN { - return crate::err(Error::new(BYTES_LEN, len)); + pub fn from_slice(b: &[u8]) -> Result { + if b.len() != 16 { + return Err(ErrorKind::InvalidLength { + expected: ExpectedLength::Exact(16), + found: b.len(), + }.into()); } let mut bytes: Bytes = [0; 16]; @@ -407,18 +404,8 @@ impl Builder { /// /// assert!(builder.is_err()); /// ``` - pub fn from_slice(b: &[u8]) -> Result { - const BYTES_LEN: usize = 16; - - let len = b.len(); - - if len != BYTES_LEN { - return crate::err(Error::new(BYTES_LEN, len)); - } - - let mut bytes: crate::Bytes = [0; 16]; - bytes.copy_from_slice(b); - Ok(Self::from_bytes(bytes)) + pub fn from_slice(b: &[u8]) -> Result { + Ok(Builder(*Uuid::from_slice(b)?.as_bytes())) } /// Creates a `Builder` from four field values. @@ -503,42 +490,33 @@ impl Builder { } /// Specifies the variant of the UUID. - pub fn set_variant(&mut self, v: crate::Variant) -> &mut Self { - let byte = self.0[8]; - - self.0[8] = match v { - crate::Variant::NCS => byte & 0x7f, - crate::Variant::RFC4122 => (byte & 0x3f) | 0x80, - crate::Variant::Microsoft => (byte & 0x1f) | 0xc0, - crate::Variant::Future => (byte & 0x1f) | 0xe0, - }; - + pub fn set_variant(&mut self, v: Variant) -> &mut Self { + *self = Builder(self.0).with_variant(v); self } /// Specifies the variant of the UUID. - pub const fn with_variant(mut self, v: crate::Variant) -> Self { + pub const fn with_variant(mut self, v: Variant) -> Self { let byte = self.0[8]; self.0[8] = match v { - crate::Variant::NCS => byte & 0x7f, - crate::Variant::RFC4122 => (byte & 0x3f) | 0x80, - crate::Variant::Microsoft => (byte & 0x1f) | 0xc0, - crate::Variant::Future => (byte & 0x1f) | 0xe0, + Variant::NCS => byte & 0x7f, + Variant::RFC4122 => (byte & 0x3f) | 0x80, + Variant::Microsoft => (byte & 0x1f) | 0xc0, + Variant::Future => (byte & 0x1f) | 0xe0, }; self } /// Specifies the version number of the UUID. - pub fn set_version(&mut self, v: crate::Version) -> &mut Self { - self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); - + pub fn set_version(&mut self, v: Version) -> &mut Self { + *self = Builder(self.0).with_version(v); self } /// Specifies the version number of the UUID. - pub const fn with_version(mut self, v: crate::Version) -> Self { + pub const fn with_version(mut self, v: Version) -> Self { self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); self diff --git a/src/builder/error.rs b/src/builder/error.rs deleted file mode 100644 index 2c42798f6..000000000 --- a/src/builder/error.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::std::fmt; - -/// The error that can occur when creating a [`Uuid`]. -/// -/// [`Uuid`]: struct.Uuid.html -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub(crate) struct Error { - expected: usize, - found: usize, -} - -impl Error { - /// The expected number of bytes. - #[inline] - const fn expected(&self) -> usize { - self.expected - } - - /// The number of bytes found. - #[inline] - const fn found(&self) -> usize { - self.found - } - - /// Create a new [`UuidError`]. - /// - /// [`UuidError`]: struct.UuidError.html - #[inline] - pub(crate) const fn new(expected: usize, found: usize) -> Self { - Error { expected, found } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "invalid bytes length: expected {}, found {}", - self.expected(), - self.found() - ) - } -} - -#[cfg(feature = "std")] -mod std_support { - use super::*; - - use crate::std::error; - - impl error::Error for Error {} -} diff --git a/src/error.rs b/src/error.rs index d572942d8..8b488bafd 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,39 +1,135 @@ use crate::std::fmt; -use crate::{builder, parser}; /// A general error that can occur when working with UUIDs. -// TODO: improve the doc -// BODY: This detail should be fine for initial merge #[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Error(Inner); +pub struct Error(pub(crate) ErrorKind); -pub(crate) fn err(err: impl Into) -> Result { - Err(err.into()) +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) enum ErrorKind { + /// Invalid character in the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidCharacter { + /// The expected characters. + expected: &'static str, + /// The invalid character found. + found: char, + /// The invalid character position. + index: usize, + /// Indicates the [`Uuid`] starts with `urn:uuid:`. + /// + /// This is a special case for [`Urn`] adapter parsing. + /// + /// [`Uuid`]: ../Uuid.html + urn: UrnPrefix, + }, + /// Invalid number of segments in the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidGroupCount { + /// The expected number of segments. + expected: ExpectedLength, + /// The number of segments found. + found: usize, + }, + /// Invalid length of a segment in a [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidGroupLength { + /// The expected length of the segment. + expected: ExpectedLength, + /// The length of segment found. + found: usize, + /// The segment with invalid length. + group: usize, + }, + /// Invalid length of the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidLength { + /// The expected length(s). + expected: ExpectedLength, + /// The invalid length found. + found: usize, + }, } -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -enum Inner { - Build(builder::Error), - Parser(parser::Error), +/// The expected length. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub(crate) enum ExpectedLength { + /// Expected any one of the given values. + Any(&'static [usize]), + /// Expected the given value. + Exact(usize), } -impl From for Error { - fn from(err: builder::Error) -> Self { - Error(Inner::Build(err)) +/// Urn prefix value. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub(crate) enum UrnPrefix { + /// The `urn:uuid:` prefix should optionally provided. + Optional, +} + +impl fmt::Display for ExpectedLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + ExpectedLength::Any(crits) => write!(f, "one of {:?}", crits), + ExpectedLength::Exact(crit) => write!(f, "{}", crit), + } } } -impl From for Error { - fn from(err: parser::Error) -> Self { - Error(Inner::Parser(err)) +impl From for Error { + fn from(kind: ErrorKind) -> Self { + Error(kind) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: ", match self.0 { + ErrorKind::InvalidCharacter { .. } => "invalid character", + ErrorKind::InvalidGroupCount { .. } => "invalid number of groups", + ErrorKind::InvalidGroupLength { .. } => "invalid group length", + ErrorKind::InvalidLength { .. } => "invalid length", + })?; + match self.0 { - Inner::Build(ref err) => fmt::Display::fmt(&err, f), - Inner::Parser(ref err) => fmt::Display::fmt(&err, f), + ErrorKind::InvalidCharacter { + expected, + found, + index, + urn, + } => { + let urn_str = match urn { + UrnPrefix::Optional => { + " an optional prefix of `urn:uuid:` followed by" + } + }; + + write!( + f, + "expected{} {}, found {} at {}", + urn_str, expected, found, index + ) + } + ErrorKind::InvalidGroupCount { + ref expected, + found, + } => write!(f, "expected {}, found {}", expected, found), + ErrorKind::InvalidGroupLength { + ref expected, + found, + group, + } => write!( + f, + "expected {}, found {} in group {}", + expected, found, group, + ), + ErrorKind::InvalidLength { + ref expected, + found, + } => write!(f, "expected {}, found {}", expected, found), } } } @@ -43,26 +139,5 @@ mod std_support { use super::*; use crate::std::error; - impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self.0 { - Inner::Build(ref err) => Some(err), - Inner::Parser(ref err) => Some(err), - } - } - } -} - -#[cfg(test)] -mod test_util { - use super::*; - - impl Error { - pub(crate) fn expect_parser(self) -> parser::Error { - match self.0 { - Inner::Parser(err) => err, - _ => panic!("expected a `parser::Error` variant"), - } - } - } + impl error::Error for Error { } } diff --git a/src/lib.rs b/src/lib.rs index 2e2c650fd..7e300fa6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -208,10 +208,7 @@ mod v5; #[cfg(all(windows, feature = "winapi"))] mod winapi_support; -use crate::{ - error::*, - std::convert, -}; +use crate::std::convert; pub use crate::error::Error; diff --git a/src/parser/mod.rs b/src/parser.rs similarity index 63% rename from src/parser/mod.rs rename to src/parser.rs index 0ab341fd1..70a046f78 100644 --- a/src/parser/mod.rs +++ b/src/parser.rs @@ -13,13 +13,10 @@ //! //! [`Uuid`]: ../struct.Uuid.html -pub(crate) mod error; -pub(crate) use self::error::Error; - -use crate::{fmt, std::str, Uuid}; +use crate::{fmt, std::str, error::*, Uuid}; impl str::FromStr for Uuid { - type Err = crate::Error; + type Err = Error; fn from_str(uuid_str: &str) -> Result { Uuid::parse_str(uuid_str) @@ -49,7 +46,7 @@ impl Uuid { /// /// Any of the formats generated by this module (simple, hyphenated, urn) /// are supported by this parsing function. - pub fn parse_str(mut input: &str) -> Result { + pub fn parse_str(mut input: &str) -> Result { // Ensure length is valid for any of the supported formats let len = input.len(); @@ -59,13 +56,13 @@ impl Uuid { len, &[fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH], ) { - return crate::err(Error::InvalidLength { - expected: error::ExpectedLength::Any(&[ + return Err(ErrorKind::InvalidLength { + expected: ExpectedLength::Any(&[ fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH, ]), found: len, - }); + }.into()); } // `digit` counts only hexadecimal digits, `i_char` counts all chars. @@ -77,52 +74,46 @@ impl Uuid { for (i_char, chr) in input.bytes().enumerate() { if digit as usize >= fmt::Simple::LENGTH && group != 4 { if group == 0 { - return crate::err(Error::InvalidLength { - expected: error::ExpectedLength::Any(&[ + return Err(ErrorKind::InvalidLength { + expected: ExpectedLength::Any(&[ fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH, ]), found: len, - }); + }.into()); } - return crate::err(Error::InvalidGroupCount { - expected: error::ExpectedLength::Any(&[1, 5]), + return Err(ErrorKind::InvalidGroupCount { + expected: ExpectedLength::Any(&[1, 5]), found: group + 1, - }); + }.into()); } if digit % 2 == 0 { // First digit of the byte. match chr { - // Calulate upper half. + // Calculate upper half. b'0'..=b'9' => acc = chr - b'0', b'a'..=b'f' => acc = chr - b'a' + 10, b'A'..=b'F' => acc = chr - b'A' + 10, // Found a group delimiter b'-' => { - // TODO: remove the u8 cast - // BODY: this only needed until we switch to - // ParseError if ACC_GROUP_LENS[group] as u8 != digit { // Calculate how many digits this group consists of // in the input. let found = if group > 0 { - // TODO: remove the u8 cast - // BODY: this only needed until we switch to - // ParseError digit - ACC_GROUP_LENS[group - 1] as u8 } else { digit }; - return crate::err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact( + return Err(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact( GROUP_LENS[group], ), found: found as usize, group, - }); + }.into()); } // Next group, decrement digit, it is incremented again // at the bottom. @@ -130,12 +121,12 @@ impl Uuid { digit -= 1; } _ => { - return crate::err(Error::InvalidCharacter { + return Err(ErrorKind::InvalidCharacter { expected: "0123456789abcdefABCDEF-", found: input[i_char..].chars().next().unwrap(), index: i_char, - urn: error::UrnPrefix::Optional, - }); + urn: UrnPrefix::Optional, + }.into()); } } } else { @@ -148,29 +139,26 @@ impl Uuid { b'-' => { // The byte isn't complete yet. let found = if group > 0 { - // TODO: remove the u8 cast - // BODY: this only needed until we switch to - // ParseError digit - ACC_GROUP_LENS[group - 1] as u8 } else { digit }; - return crate::err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact( + return Err(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact( GROUP_LENS[group], ), found: found as usize, group, - }); + }.into()); } _ => { - return crate::err(Error::InvalidCharacter { + return Err(ErrorKind::InvalidCharacter { expected: "0123456789abcdefABCDEF-", found: input[i_char..].chars().next().unwrap(), index: i_char, - urn: error::UrnPrefix::Optional, - }); + urn: UrnPrefix::Optional, + }.into()); } } buffer[(digit / 2) as usize] = acc; @@ -179,15 +167,12 @@ impl Uuid { } // Now check the last group. - // TODO: remove the u8 cast - // BODY: this only needed until we switch to - // ParseError if ACC_GROUP_LENS[4] as u8 != digit { - return crate::err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact(GROUP_LENS[4]), + return Err(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact(GROUP_LENS[4]), found: (digit as usize - ACC_GROUP_LENS[3]), group, - }); + }.into()); } Ok(Uuid::from_bytes(buffer)) @@ -201,176 +186,161 @@ mod tests { #[test] fn test_parse_uuid_v4() { - const EXPECTED_UUID_LENGTHS: error::ExpectedLength = - error::ExpectedLength::Any(&[ + const EXPECTED_UUID_LENGTHS: ExpectedLength = + ExpectedLength::Any(&[ fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH, ]); - const EXPECTED_GROUP_COUNTS: error::ExpectedLength = - error::ExpectedLength::Any(&[1, 5]); + const EXPECTED_GROUP_COUNTS: ExpectedLength = + ExpectedLength::Any(&[1, 5]); const EXPECTED_CHARS: &'static str = "0123456789abcdefABCDEF-"; // Invalid assert_eq!( - Uuid::parse_str("").map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str(""), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 0, - }) + })) ); assert_eq!( - Uuid::parse_str("!").map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("!"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 1 - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 37, - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 35 - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidCharacter { + Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"), + Err(Error(ErrorKind::InvalidCharacter { expected: EXPECTED_CHARS, found: 'G', index: 20, - urn: error::UrnPrefix::Optional, - }) + urn: UrnPrefix::Optional, + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupCount { + Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4"), + Err(Error(ErrorKind::InvalidGroupCount { expected: EXPECTED_GROUP_COUNTS, found: 2 - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupCount { + Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4"), + Err(Error(ErrorKind::InvalidGroupCount { expected: EXPECTED_GROUP_COUNTS, found: 3, - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupCount { + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"), + Err(Error(ErrorKind::InvalidGroupCount { expected: EXPECTED_GROUP_COUNTS, found: 4, - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("F9168C5E-CEB2-4faa"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 18, - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidCharacter { + Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"), + Err(Error(ErrorKind::InvalidCharacter { expected: EXPECTED_CHARS, found: 'X', index: 18, - urn: error::UrnPrefix::Optional, - }) + urn: UrnPrefix::Optional, + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact(4), + Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"), + Err(Error(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact(4), found: 3, group: 1, - }) + })) ); // (group, found, expecting) // assert_eq!( - Uuid::parse_str("01020304-1112-2122-3132-41424344") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact(12), + Uuid::parse_str("01020304-1112-2122-3132-41424344"), + Err(Error(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact(12), found: 8, group: 4, - }) + })) ); assert_eq!( - Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 31, - }) + })) ); assert_eq!( - Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 33, - }) + })) ); assert_eq!( - Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 33, - }) + })) ); assert_eq!( - Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidCharacter { + Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"), + Err(Error(ErrorKind::InvalidCharacter { expected: EXPECTED_CHARS, found: '%', index: 15, - urn: error::UrnPrefix::Optional, - }) + urn: UrnPrefix::Optional, + })) ); assert_eq!( - Uuid::parse_str("231231212212423424324323477343246663") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("231231212212423424324323477343246663"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 36, - }) + })) ); // Valid @@ -403,40 +373,36 @@ mod tests { // Test error reporting assert_eq!( - Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidLength { + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"), + Err(Error(ErrorKind::InvalidLength { expected: EXPECTED_UUID_LENGTHS, found: 31, - }) + })) ); assert_eq!( - Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidCharacter { + Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"), + Err(Error(ErrorKind::InvalidCharacter { expected: EXPECTED_CHARS, found: 'X', index: 6, - urn: error::UrnPrefix::Optional, - }) + urn: UrnPrefix::Optional, + })) ); assert_eq!( - Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact(8), + Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"), + Err(Error(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact(8), found: 6, group: 0, - }) + })) ); assert_eq!( - Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4") - .map_err(crate::Error::expect_parser), - Err(Error::InvalidGroupLength { - expected: error::ExpectedLength::Exact(4), + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"), + Err(Error(ErrorKind::InvalidGroupLength { + expected: ExpectedLength::Exact(4), found: 5, group: 3, - }) + })) ); } } diff --git a/src/parser/error.rs b/src/parser/error.rs deleted file mode 100644 index 0dec2fff7..000000000 --- a/src/parser/error.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::std::fmt; - -/// An error that can occur while parsing a [`Uuid`] string. -/// -/// [`Uuid`]: ../struct.Uuid.html -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[allow(clippy::enum_variant_names)] -pub(crate) enum Error { - /// Invalid character in the [`Uuid`] string. - /// - /// [`Uuid`]: ../struct.Uuid.html - InvalidCharacter { - /// The expected characters. - expected: &'static str, - /// The invalid character found. - found: char, - /// The invalid character position. - index: usize, - /// Indicates the [`Uuid`] starts with `urn:uuid:`. - /// - /// This is a special case for [`Urn`] adapter parsing. - /// - /// [`Uuid`]: ../Uuid.html - urn: UrnPrefix, - }, - /// Invalid number of segments in the [`Uuid`] string. - /// - /// [`Uuid`]: ../struct.Uuid.html - InvalidGroupCount { - /// The expected number of segments. - // TODO: explain multiple segment count. - // BODY: Parsers can expect a range of Uuid segment count. - // This needs to be expanded on. - expected: ExpectedLength, - /// The number of segments found. - found: usize, - }, - /// Invalid length of a segment in a [`Uuid`] string. - /// - /// [`Uuid`]: ../struct.Uuid.html - InvalidGroupLength { - /// The expected length of the segment. - expected: ExpectedLength, - /// The length of segment found. - found: usize, - /// The segment with invalid length. - group: usize, - }, - /// Invalid length of the [`Uuid`] string. - /// - /// [`Uuid`]: ../struct.Uuid.html - InvalidLength { - /// The expected length(s). - // TODO: explain multiple lengths. - // BODY: Parsers can expect a range of Uuid lenghts. - // This needs to be expanded on. - expected: ExpectedLength, - /// The invalid length found. - found: usize, - }, -} - -/// The expected length. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub(crate) enum ExpectedLength { - /// Expected any one of the given values. - Any(&'static [usize]), - /// Expected the given value. - Exact(usize), -} - -/// Urn prefix value. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub(crate) enum UrnPrefix { - /// The `urn:uuid:` prefix should optionally provided. - Optional, -} - -impl Error { - fn _description(&self) -> &str { - match *self { - Error::InvalidCharacter { .. } => "invalid character", - Error::InvalidGroupCount { .. } => "invalid number of groups", - Error::InvalidGroupLength { .. } => "invalid group length", - Error::InvalidLength { .. } => "invalid length", - } - } -} - -impl fmt::Display for ExpectedLength { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ExpectedLength::Any(crits) => write!(f, "one of {:?}", crits), - ExpectedLength::Exact(crit) => write!(f, "{}", crit), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: ", self._description())?; - - match *self { - Error::InvalidCharacter { - expected, - found, - index, - urn, - } => { - let urn_str = match urn { - UrnPrefix::Optional => { - " an optional prefix of `urn:uuid:` followed by" - } - }; - - write!( - f, - "expected{} {}, found {} at {}", - urn_str, expected, found, index - ) - } - Error::InvalidGroupCount { - ref expected, - found, - } => write!(f, "expected {}, found {}", expected, found), - Error::InvalidGroupLength { - ref expected, - found, - group, - } => write!( - f, - "expected {}, found {} in group {}", - expected, found, group, - ), - Error::InvalidLength { - ref expected, - found, - } => write!(f, "expected {}, found {}", expected, found), - } - } -} - -#[cfg(feature = "std")] -mod std_support { - use super::*; - use crate::std::error; - - impl error::Error for Error {} -} From 9c07eb0281e6fa6de2bce6dd5ed52d5228415127 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Fri, 29 Oct 2021 22:01:06 +1000 Subject: [PATCH 7/8] simplify internal module layout --- src/builder.rs | 50 +++++++++++--------- src/error.rs | 19 +++++--- src/fmt.rs | 8 ++-- src/lib.rs | 105 +++++++++++++++++------------------------- src/parser.rs | 43 +++++++++-------- src/prelude.rs | 48 ------------------- src/serde_support.rs | 50 ++++++++++---------- src/slog_support.rs | 11 ++--- src/test_util.rs | 26 ----------- src/v1.rs | 9 ++-- src/v3.rs | 3 +- src/v4.rs | 4 +- src/v5.rs | 3 +- src/winapi_support.rs | 3 +- 14 files changed, 157 insertions(+), 225 deletions(-) delete mode 100644 src/prelude.rs delete mode 100644 src/test_util.rs diff --git a/src/builder.rs b/src/builder.rs index c17dd44cd..74e0ed0cb 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -13,8 +13,30 @@ //! //! [`Uuid`]: ../struct.Uuid.html -use crate::error::*; -use crate::prelude::*; +use crate::{error::*, Bytes, Uuid, Variant, Version}; + +/// A builder struct for creating a UUID. +/// +/// # Examples +/// +/// Creating a v4 UUID from externally generated bytes: +/// +/// ``` +/// use uuid::{Builder, Variant, Version}; +/// +/// # let rng = || [ +/// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, +/// # 145, 63, 62, +/// # ]; +/// let random_bytes = rng(); +/// let uuid = Builder::from_bytes(random_bytes) +/// .set_variant(Variant::RFC4122) +/// .set_version(Version::Random) +/// .build(); +/// ``` +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct Builder(Bytes); impl Uuid { /// The 'nil UUID'. @@ -63,12 +85,7 @@ impl Uuid { /// "ab3f1097-501e-b736-0c03-0938362b0809" /// ); /// ``` - pub const fn from_fields( - d1: u32, - d2: u16, - d3: u16, - d4: &[u8; 8], - ) -> Uuid { + pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Uuid { Uuid::from_bytes([ (d1 >> 24) as u8, (d1 >> 16) as u8, @@ -113,12 +130,7 @@ impl Uuid { /// "97103fab-1e50-36b7-0c03-0938362b0809" /// ); /// ``` - pub const fn from_fields_le( - d1: u32, - d2: u16, - d3: u16, - d4: &[u8], - ) -> Uuid { + pub const fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid { Uuid::from_bytes([ d1 as u8, (d1 >> 8) as u8, @@ -307,7 +319,8 @@ impl Uuid { return Err(ErrorKind::InvalidLength { expected: ExpectedLength::Exact(16), found: b.len(), - }.into()); + } + .into()); } let mut bytes: Bytes = [0; 16]; @@ -427,12 +440,7 @@ impl Builder { /// "ab3f1097-501e-b736-0c03-0938362b0809" /// ); /// ``` - pub const fn from_fields( - d1: u32, - d2: u16, - d3: u16, - d4: &[u8; 8], - ) -> Self { + pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self { Builder::from_bytes(*Uuid::from_fields(d1, d2, d3, d4).as_bytes()) } diff --git a/src/error.rs b/src/error.rs index 8b488bafd..63010fcc5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -87,12 +87,17 @@ impl From for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: ", match self.0 { - ErrorKind::InvalidCharacter { .. } => "invalid character", - ErrorKind::InvalidGroupCount { .. } => "invalid number of groups", - ErrorKind::InvalidGroupLength { .. } => "invalid group length", - ErrorKind::InvalidLength { .. } => "invalid length", - })?; + write!( + f, + "{}: ", + match self.0 { + ErrorKind::InvalidCharacter { .. } => "invalid character", + ErrorKind::InvalidGroupCount { .. } => + "invalid number of groups", + ErrorKind::InvalidGroupLength { .. } => "invalid group length", + ErrorKind::InvalidLength { .. } => "invalid length", + } + )?; match self.0 { ErrorKind::InvalidCharacter { @@ -139,5 +144,5 @@ mod std_support { use super::*; use crate::std::error; - impl error::Error for Error { } + impl error::Error for Error {} } diff --git a/src/fmt.rs b/src/fmt.rs index 850f67fc4..83367194d 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -11,8 +11,10 @@ //! Adapters for various formats for UUIDs -use crate::prelude::*; -use crate::std::{borrow::Borrow, fmt, str}; +use crate::{ + std::{borrow::Borrow, fmt, str}, + Uuid, Variant, +}; impl std::fmt::Debug for Uuid { #[inline] @@ -1060,7 +1062,7 @@ impl_fmt_traits! { #[cfg(test)] mod tests { - use crate::prelude::*; + use super::*; #[test] fn hyphenated_trailing() { diff --git a/src/lib.rs b/src/lib.rs index 7e300fa6b..d98841ffc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -187,7 +187,6 @@ extern crate core as std; mod builder; mod error; mod parser; -mod prelude; pub mod fmt; #[cfg(feature = "v1")] @@ -197,8 +196,6 @@ pub mod v1; mod serde_support; #[cfg(feature = "slog")] mod slog_support; -#[cfg(test)] -mod test_util; #[cfg(feature = "v3")] mod v3; #[cfg(feature = "v4")] @@ -210,30 +207,7 @@ mod winapi_support; use crate::std::convert; -pub use crate::error::Error; - -/// A builder struct for creating a UUID. -/// -/// # Examples -/// -/// Creating a v4 UUID from externally generated bytes: -/// -/// ``` -/// use uuid::{Builder, Variant, Version}; -/// -/// # let rng = || [ -/// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, -/// # 145, 63, 62, -/// # ]; -/// let random_bytes = rng(); -/// let uuid = Builder::from_bytes(random_bytes) -/// .set_variant(Variant::RFC4122) -/// .set_version(Version::Random) -/// .build(); -/// ``` -#[allow(missing_copy_implementations)] -#[derive(Debug)] -pub struct Builder(Bytes); +pub use crate::{builder::Builder, error::Error}; /// A 128-bit (16 byte) buffer containing the ID. pub type Bytes = [u8; 16]; @@ -401,14 +375,11 @@ impl Uuid { | (bytes[2] as u32) << 8 | (bytes[3] as u32); - let d2 = - (bytes[4] as u16) << 8 | (bytes[5] as u16); + let d2 = (bytes[4] as u16) << 8 | (bytes[5] as u16); - let d3 = - (bytes[6] as u16) << 8 | (bytes[7] as u16); + let d3 = (bytes[6] as u16) << 8 | (bytes[7] as u16); - let d4: &[u8; 8] = - convert::TryInto::try_into(&bytes[8..16]).unwrap(); + let d4: &[u8; 8] = convert::TryInto::try_into(&bytes[8..16]).unwrap(); (d1, d2, d3, d4) } @@ -444,11 +415,9 @@ impl Uuid { | (self.as_bytes()[2] as u32) << 16 | (self.as_bytes()[3] as u32) << 24; - let d2 = - (self.as_bytes()[4] as u16) | (self.as_bytes()[5] as u16) << 8; + let d2 = (self.as_bytes()[4] as u16) | (self.as_bytes()[5] as u16) << 8; - let d3 = - (self.as_bytes()[6] as u16) | (self.as_bytes()[7] as u16) << 8; + let d3 = (self.as_bytes()[6] as u16) | (self.as_bytes()[7] as u16) << 8; let d4: &[u8; 8] = convert::TryInto::try_into(&self.as_bytes()[8..16]).unwrap(); @@ -621,11 +590,9 @@ impl AsRef<[u8]> for Uuid { #[cfg(test)] mod tests { - use crate::{ - prelude::*, - std::string::{String, ToString}, - test_util, - }; + use super::*; + + use crate::std::string::{String, ToString}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -639,11 +606,25 @@ mod tests { }; } + pub const fn new() -> Uuid { + Uuid::from_bytes([ + 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAA, 0xB6, 0xBF, 0x32, + 0x9B, 0xF3, 0x9F, 0xA1, 0xE4, + ]) + } + + pub const fn new2() -> Uuid { + Uuid::from_bytes([ + 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAB, 0xB6, 0xBF, 0x32, + 0x9B, 0xF3, 0x9F, 0xA1, 0xE4, + ]) + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_compare() { - let uuid1 = test_util::new(); - let uuid2 = test_util::new2(); + let uuid1 = new(); + let uuid2 = new2(); assert_eq!(uuid1, uuid1); assert_eq!(uuid2, uuid2); @@ -666,7 +647,7 @@ mod tests { fn test_uuid_display() { use crate::std::fmt::Write; - let uuid = test_util::new(); + let uuid = new(); let s = uuid.to_string(); let mut buffer = String::new(); @@ -683,7 +664,7 @@ mod tests { use crate::std::fmt::Write; let mut buffer = String::new(); - let uuid = test_util::new(); + let uuid = new(); check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase() || c.is_digit(10) @@ -694,9 +675,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_uuid_operator_eq() { - let uuid1 = test_util::new(); + let uuid1 = new(); let uuid1_dup = uuid1.clone(); - let uuid2 = test_util::new2(); + let uuid2 = new2(); assert!(uuid1 == uuid1); assert!(uuid1 == uuid1_dup); @@ -713,7 +694,7 @@ mod tests { fn test_uuid_to_string() { use crate::std::fmt::Write; - let uuid = test_util::new(); + let uuid = new(); let s = uuid.to_string(); let mut buffer = String::new(); @@ -730,7 +711,7 @@ mod tests { use crate::std::fmt::Write; let mut buffer = String::new(); - let uuid = test_util::new(); + let uuid = new(); check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase() || c.is_digit(10) @@ -741,7 +722,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_nil() { let nil = Uuid::nil(); - let not_nil = test_util::new(); + let not_nil = new(); let from_bytes = Uuid::from_bytes([ 4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87, ]); @@ -790,7 +771,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_get_variant() { - let uuid1 = test_util::new(); + let uuid1 = new(); let uuid2 = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); let uuid3 = @@ -813,7 +794,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_to_simple_string() { - let uuid1 = test_util::new(); + let uuid1 = new(); let s = uuid1.to_simple().to_string(); assert_eq!(s.len(), 32); @@ -823,7 +804,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_to_hyphenated_string() { - let uuid1 = test_util::new(); + let uuid1 = new(); let s = uuid1.to_hyphenated().to_string(); assert!(s.len() == 36); @@ -836,7 +817,7 @@ mod tests { use std::fmt::Write; let mut buf = String::new(); - let u = test_util::new(); + let u = new(); macro_rules! check { ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => { @@ -866,7 +847,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_to_urn_string() { - let uuid1 = test_util::new(); + let uuid1 = new(); let ss = uuid1.to_urn().to_string(); let s = &ss[9..]; @@ -878,7 +859,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_to_simple_string_matching() { - let uuid1 = test_util::new(); + let uuid1 = new(); let hs = uuid1.to_hyphenated().to_string(); let ss = uuid1.to_simple().to_string(); @@ -891,7 +872,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_string_roundtrip() { - let uuid = test_util::new(); + let uuid = new(); let hs = uuid.to_hyphenated().to_string(); let uuid_hs = Uuid::parse_str(&hs).unwrap(); @@ -935,7 +916,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_as_fields() { - let u = test_util::new(); + let u = new(); let (d1, d2, d3, d4) = u.as_fields(); assert_ne!(d1, 0); @@ -1110,7 +1091,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_as_bytes() { - let u = test_util::new(); + let u = new(); let ub = u.as_bytes(); let ur = u.as_ref(); @@ -1139,8 +1120,8 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_iterbytes_impl_for_uuid() { let mut set = std::collections::HashSet::new(); - let id1 = test_util::new(); - let id2 = test_util::new2(); + let id1 = new(); + let id2 = new2(); set.insert(id1.clone()); assert!(set.contains(&id1)); diff --git a/src/parser.rs b/src/parser.rs index 70a046f78..1dec388bd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,7 +13,7 @@ //! //! [`Uuid`]: ../struct.Uuid.html -use crate::{fmt, std::str, error::*, Uuid}; +use crate::{error::*, fmt, std::str, Uuid}; impl str::FromStr for Uuid { type Err = Error; @@ -62,7 +62,8 @@ impl Uuid { fmt::Simple::LENGTH, ]), found: len, - }.into()); + } + .into()); } // `digit` counts only hexadecimal digits, `i_char` counts all chars. @@ -80,13 +81,15 @@ impl Uuid { fmt::Simple::LENGTH, ]), found: len, - }.into()); + } + .into()); } return Err(ErrorKind::InvalidGroupCount { expected: ExpectedLength::Any(&[1, 5]), found: group + 1, - }.into()); + } + .into()); } if digit % 2 == 0 { @@ -113,7 +116,8 @@ impl Uuid { ), found: found as usize, group, - }.into()); + } + .into()); } // Next group, decrement digit, it is incremented again // at the bottom. @@ -126,7 +130,8 @@ impl Uuid { found: input[i_char..].chars().next().unwrap(), index: i_char, urn: UrnPrefix::Optional, - }.into()); + } + .into()); } } } else { @@ -145,12 +150,11 @@ impl Uuid { }; return Err(ErrorKind::InvalidGroupLength { - expected: ExpectedLength::Exact( - GROUP_LENS[group], - ), + expected: ExpectedLength::Exact(GROUP_LENS[group]), found: found as usize, group, - }.into()); + } + .into()); } _ => { return Err(ErrorKind::InvalidCharacter { @@ -158,7 +162,8 @@ impl Uuid { found: input[i_char..].chars().next().unwrap(), index: i_char, urn: UrnPrefix::Optional, - }.into()); + } + .into()); } } buffer[(digit / 2) as usize] = acc; @@ -172,7 +177,8 @@ impl Uuid { expected: ExpectedLength::Exact(GROUP_LENS[4]), found: (digit as usize - ACC_GROUP_LENS[3]), group, - }.into()); + } + .into()); } Ok(Uuid::from_bytes(buffer)) @@ -182,15 +188,14 @@ impl Uuid { #[cfg(test)] mod tests { use super::*; - use crate::{fmt, std::string::ToString, test_util}; + use crate::{fmt, std::string::ToString, tests::new}; #[test] fn test_parse_uuid_v4() { - const EXPECTED_UUID_LENGTHS: ExpectedLength = - ExpectedLength::Any(&[ - fmt::Hyphenated::LENGTH, - fmt::Simple::LENGTH, - ]); + const EXPECTED_UUID_LENGTHS: ExpectedLength = ExpectedLength::Any(&[ + fmt::Hyphenated::LENGTH, + fmt::Simple::LENGTH, + ]); const EXPECTED_GROUP_COUNTS: ExpectedLength = ExpectedLength::Any(&[1, 5]); @@ -366,7 +371,7 @@ mod tests { ); // Round-trip - let uuid_orig = test_util::new(); + let uuid_orig = new(); let orig_str = uuid_orig.to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); diff --git a/src/prelude.rs b/src/prelude.rs deleted file mode 100644 index 7d269f395..000000000 --- a/src/prelude.rs +++ /dev/null @@ -1,48 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The [`uuid`] prelude. -//! -//! This module contains the most important items of the [`uuid`] crate. -//! -//! To use the prelude, include the following in your crate root: -//! -//! ```rust -//! extern crate uuid; -//! ``` -//! -//! # Prelude Contents -//! -//! Currently the prelude reexports the following: -//! -//! [`uuid`]`::{`[`Error`], [`Uuid`], [`Variant`], [`Version`], -//! builder::[`Builder`]`}`: The fundamental types used in [`uuid`] crate. -//! -//! [`uuid`]: ../index.html -//! [`Error`]: ../enum.Error.html -//! [`Uuid`]: ../struct.Uuid.html -//! [`Variant`]: ../enum.Variant.html -//! [`Version`]: ../enum.Version.html -//! [`Builder`]: ../builder/struct.Builder.html -#![cfg_attr( - feature = "v1", - doc = " -[`uuid::v1`]`::{`[`ClockSequence`],[`Context`]`}`: The types useful for -handling uuid version 1. Requires feature `v1`. - -[`uuid::v1`]: ../v1/index.html -[`Context`]: ../v1/struct.Context.html -[`ClockSequence`]: ../v1/trait.ClockSequence.html" -)] - -pub use super::{Builder, Bytes, Error, Uuid, Variant, Version}; -#[cfg(feature = "v1")] -pub use crate::v1::{ClockSequence, Context}; diff --git a/src/serde_support.rs b/src/serde_support.rs index 8c5d687b6..6fb1d80a9 100644 --- a/src/serde_support.rs +++ b/src/serde_support.rs @@ -9,8 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::prelude::*; -use core::fmt; +use crate::{std::fmt, Uuid}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; impl Serialize for Uuid { @@ -74,9 +73,9 @@ impl<'de> Deserialize<'de> for Uuid { #[cfg(test)] mod serde_tests { - use serde_test::{Compact, Configure, Readable, Token}; + use super::*; - use crate::prelude::*; + use serde_test::{Compact, Configure, Readable, Token}; #[test] fn test_serialize_readable() { @@ -89,26 +88,29 @@ mod serde_tests { fn test_serialize_compact() { let uuid_bytes = b"F9168C5E-CEB2-4F"; let u = Uuid::from_slice(uuid_bytes).unwrap(); - serde_test::assert_tokens(&u.compact(), &[ - serde_test::Token::Tuple { len: 16 }, - serde_test::Token::U8(uuid_bytes[0]), - serde_test::Token::U8(uuid_bytes[1]), - serde_test::Token::U8(uuid_bytes[2]), - serde_test::Token::U8(uuid_bytes[3]), - serde_test::Token::U8(uuid_bytes[4]), - serde_test::Token::U8(uuid_bytes[5]), - serde_test::Token::U8(uuid_bytes[6]), - serde_test::Token::U8(uuid_bytes[7]), - serde_test::Token::U8(uuid_bytes[8]), - serde_test::Token::U8(uuid_bytes[9]), - serde_test::Token::U8(uuid_bytes[10]), - serde_test::Token::U8(uuid_bytes[11]), - serde_test::Token::U8(uuid_bytes[12]), - serde_test::Token::U8(uuid_bytes[13]), - serde_test::Token::U8(uuid_bytes[14]), - serde_test::Token::U8(uuid_bytes[15]), - serde_test::Token::TupleEnd, - ]); + serde_test::assert_tokens( + &u.compact(), + &[ + serde_test::Token::Tuple { len: 16 }, + serde_test::Token::U8(uuid_bytes[0]), + serde_test::Token::U8(uuid_bytes[1]), + serde_test::Token::U8(uuid_bytes[2]), + serde_test::Token::U8(uuid_bytes[3]), + serde_test::Token::U8(uuid_bytes[4]), + serde_test::Token::U8(uuid_bytes[5]), + serde_test::Token::U8(uuid_bytes[6]), + serde_test::Token::U8(uuid_bytes[7]), + serde_test::Token::U8(uuid_bytes[8]), + serde_test::Token::U8(uuid_bytes[9]), + serde_test::Token::U8(uuid_bytes[10]), + serde_test::Token::U8(uuid_bytes[11]), + serde_test::Token::U8(uuid_bytes[12]), + serde_test::Token::U8(uuid_bytes[13]), + serde_test::Token::U8(uuid_bytes[14]), + serde_test::Token::U8(uuid_bytes[15]), + serde_test::Token::TupleEnd, + ], + ); } #[test] diff --git a/src/slog_support.rs b/src/slog_support.rs index f03b709a8..2d6e817ba 100644 --- a/src/slog_support.rs +++ b/src/slog_support.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::prelude::*; +use crate::Uuid; impl slog::Value for Uuid { fn serialize( @@ -24,15 +24,14 @@ impl slog::Value for Uuid { #[cfg(test)] mod tests { + use crate::tests::new; + + use slog::{self, crit, Drain}; #[test] fn test_slog_kv() { - use crate::test_util; - use slog; - use slog::{crit, Drain}; - let root = slog::Logger::root(slog::Discard.fuse(), slog::o!()); - let u1 = test_util::new(); + let u1 = new(); crit!(root, "test"; "u1" => u1); } } diff --git a/src/test_util.rs b/src/test_util.rs deleted file mode 100644 index 9eec11750..000000000 --- a/src/test_util.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use crate::prelude::*; - -pub const fn new() -> Uuid { - Uuid::from_bytes([ - 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAA, 0xB6, 0xBF, 0x32, 0x9B, - 0xF3, 0x9F, 0xA1, 0xE4, - ]) -} - -pub const fn new2() -> Uuid { - Uuid::from_bytes([ - 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAB, 0xB6, 0xBF, 0x32, 0x9B, - 0xF3, 0x9F, 0xA1, 0xE4, - ]) -} diff --git a/src/v1.rs b/src/v1.rs index 9a4694153..bf31e9678 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -2,7 +2,8 @@ //! //! Note that you need feature `v1` in order to use these features. -use crate::prelude::*; +use crate::{Uuid, Version}; + use atomic::Atomic; /// The number of 100 ns ticks between the UUID epoch @@ -240,8 +241,8 @@ impl Uuid { | (self.as_bytes()[9] as u16); Some(Timestamp::from_rfc4122(ticks, counter)) - }, - _ => None + } + _ => None, } } } @@ -275,7 +276,7 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - use crate::std::string::ToString; + use crate::{std::string::ToString, Variant}; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] diff --git a/src/v3.rs b/src/v3.rs index af85d93c0..c6f7c7554 100644 --- a/src/v3.rs +++ b/src/v3.rs @@ -1,4 +1,5 @@ -use crate::prelude::*; +use crate::{Uuid, Variant, Version}; + use md5::{Digest, Md5}; impl Uuid { diff --git a/src/v4.rs b/src/v4.rs index f74bff87f..0dfd0c029 100644 --- a/src/v4.rs +++ b/src/v4.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{Uuid, Variant, Version}; impl Uuid { /// Creates a random UUID. @@ -40,7 +40,7 @@ impl Uuid { #[cfg(test)] mod tests { - use crate::prelude::*; + use super::*; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; diff --git a/src/v5.rs b/src/v5.rs index 26bf3fab2..146aa27f3 100644 --- a/src/v5.rs +++ b/src/v5.rs @@ -1,4 +1,5 @@ -use crate::prelude::*; +use crate::{Uuid, Variant, Version}; + use sha1::{Digest, Sha1}; impl Uuid { diff --git a/src/winapi_support.rs b/src/winapi_support.rs index 417669f9d..8de29172c 100644 --- a/src/winapi_support.rs +++ b/src/winapi_support.rs @@ -1,4 +1,5 @@ -use crate::prelude::*; +use crate::Uuid; + use winapi::shared::guiddef; #[cfg(feature = "guid")] From cd9786f012d8e0b02db86696f041a3d2c077ce68 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Sat, 30 Oct 2021 09:29:54 +1000 Subject: [PATCH 8/8] rename wasm-bindgen feature to js --- .github/workflows/ci.yml | 7 ++-- .travis.yml | 71 ---------------------------------------- Cargo.toml | 3 +- README.md | 6 ++-- src/lib.rs | 14 +++++--- 5 files changed, 17 insertions(+), 84 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed700ecb4..5d07b54b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,9 +91,12 @@ jobs: - name: Install run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - + - name: Default features - run: wasm-pack test --node -- --features "wasm-bindgen v1 v3 v4 v5" + run: wasm-pack test --node + + - name: Version features + run: wasm-pack test --node -- --features "js v1 v3 v4 v5" embedded: name: Build / Embedded diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fcd1f031b..000000000 --- a/.travis.yml +++ /dev/null @@ -1,71 +0,0 @@ -branches: - except: - - /.*(.tmp)$/ - -language: rust - -matrix: - include: - - os: osx - rust: nightly - - rust: nightly - env: - - LABEL="cargo-web" - before_script: - - cargo install cargo-web - script: - - cargo test --features "serde std v1 v3 v4 v5" - - cargo bench --features "serde std v1 v3 v4 v5" - - cargo web build --features "v3 stdweb" - - cargo web build --features "v4 stdweb" - - cargo web build --features "v5 stdweb" - - cargo web build --features "v3 wasm-bindgen" - - cargo web build --features "v4 wasm-bindgen" - - cargo web build --features "v5 wasm-bindgen" - - rust: beta - env: - - LABEL="cargo-web" - before_script: - - cargo install cargo-web - script: - - cargo web build --features "v3 wasm-bindgen" - - cargo web build --features "v4 wasm-bindgen" - - cargo web build --features "v5 wasm-bindgen" - - rust: stable - env: - - LABEL="wasm" - before_script: - - rustup target add wasm32-unknown-unknown - script: - - cargo build --target wasm32-unknown-unknown --features "v3 wasm-bindgen" - - cargo build --target wasm32-unknown-unknown --features "v4 wasm-bindgen" - - cargo build --target wasm32-unknown-unknown --features "v5 wasm-bindgen" - - rust: stable - env: - - LABEL="no-std" - before_script: - - rustup target add thumbv6m-none-eabi - script: - - cargo build --no-default-features --target thumbv6m-none-eabi - -notifications: - email: - on_success: never - -os: linux - -script: -- cargo build --no-default-features -- cargo build --all-features -- cargo build -- cargo test --no-default-features -- cargo test --all-features -- cargo test -- cargo test --features "serde" -- cargo test --features "v1" -- cargo test --features "v3" -- cargo test --features "v4" -- cargo test --features "v5" -- cargo test --features "slog" - -sudo: false diff --git a/Cargo.toml b/Cargo.toml index db235df7f..4c01df72f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,12 +55,11 @@ repository = "uuid-rs/uuid" default = ["std"] guid = ["winapi"] std = [] -stdweb = ["getrandom", "getrandom/js"] v1 = ["atomic"] v3 = ["md-5"] v4 = ["getrandom"] v5 = ["sha-1"] -wasm-bindgen = ["getrandom", "getrandom/js"] +js = ["getrandom", "getrandom/js"] # Private [dependencies.getrandom] diff --git a/README.md b/README.md index d58281bb3..754245a22 100644 --- a/README.md +++ b/README.md @@ -49,10 +49,8 @@ various pieces of functionality: You need to enable one of the following Cargo features together with the `v4` feature if you're targeting `wasm32-unknown-unknown` target: -* `stdweb` - enables support for `OsRng` on `wasm32-unknown-unknown` via - `stdweb` combined with `cargo-web` -* `wasm-bindgen` - `wasm-bindgen` enables support for `OsRng` on - `wasm32-unknown-unknown` via [`wasm-bindgen`] +* `js` - enables support for randomness on + `wasm32-unknown-unknown` via [`getrandom`] Alternatively, you can provide a custom `getrandom` implementation yourself via [`getrandom::register_custom_getrandom`](https://docs.rs/getrandom/0.2.2/getrandom/macro.register_custom_getrandom.html). diff --git a/src/lib.rs b/src/lib.rs index d98841ffc..a8e1d651e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,11 +68,16 @@ //! //! ## WebAssembly //! -//! For WebAssembly, enable one of the following features depending -//! on your JavaScript interop toolchain of choice: +//! For WebAssembly, enable the `js` feature along with `v4` for a +//! source of randomness: //! -//! * `stdweb` - for [`stdweb`] combined with [`cargo-web`] -//! * `wasm-bindgen` - for [`wasm-bindgen`] +//! ```toml +//! [dependencies] +//! uuid = { version = "0.8", features = ["v4", "js"] } +//! ``` +//! +//! You don't need the `js` feature to use `uuid` in WebAssembly if you're +//! not enabling other features too. //! //! ## Embedded //! @@ -158,7 +163,6 @@ //! //! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen //! [`cargo-web`]: https://crates.io/crates/cargo-web -//! [`stdweb`]: https://crates.io/crates/stdweb //! [`Uuid`]: struct.Uuid.html //! [`Uuid::new_v1`]: struct.Uuid.html#method.new_v1 //! [`Uuid::new_v3`]: struct.Uuid.html#method.new_v3