Merge pull request #536 from KodrAus/feat/infallible-ctors

Make ctors that accept slices infallible using arrays and other breaking changes
This commit is contained in:
Ashley Mannix 2021-10-31 07:45:44 +10:00 committed by GitHub
commit 05ac705340
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 686 additions and 1041 deletions

View File

@ -91,9 +91,12 @@ jobs:
- name: Install - name: Install
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Default features - 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: embedded:
name: Build / Embedded name: Build / Embedded

View File

@ -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

View File

@ -51,34 +51,55 @@ status = "actively-developed"
[badges.travis-ci] [badges.travis-ci]
repository = "uuid-rs/uuid" repository = "uuid-rs/uuid"
[features]
default = ["std"]
guid = ["winapi"]
std = []
v1 = ["atomic"]
v3 = ["md-5"]
v4 = ["getrandom"]
v5 = ["sha-1"]
js = ["getrandom", "getrandom/js"]
# Private
[dependencies.getrandom] [dependencies.getrandom]
optional = true optional = true
version = "0.2" version = "0.2"
# Private
[dependencies.atomic] [dependencies.atomic]
default-features = false default-features = false
optional = true optional = true
version = "0.5" version = "0.5"
# Private
[dependencies.md-5] [dependencies.md-5]
default-features = false default-features = false
optional = true optional = true
version = "0.9" version = "0.9"
[dependencies.serde] # Private
default-features = false
optional = true
version = "1.0.56"
[dependencies.sha-1] [dependencies.sha-1]
default-features = false default-features = false
optional = true optional = true
version = "0.9" version = "0.9"
# Public: Used in trait impls on `Uuid`
[dependencies.serde]
default-features = false
optional = true
version = "1.0.56"
# Public: Used in trait impls on `Uuid`
[dependencies.slog] [dependencies.slog]
optional = true optional = true
version = "2" version = "2"
# Public: Used in `From` impls on `Uuid`
[target.'cfg(windows)'.dependencies.winapi]
optional = true
version = "0.3"
[dev-dependencies.bincode] [dev-dependencies.bincode]
version = "1.0" version = "1.0"
@ -97,18 +118,3 @@ version = "0.2"
[dev-dependencies.wasm-bindgen-test] [dev-dependencies.wasm-bindgen-test]
version = "0.3" 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"

View File

@ -49,10 +49,8 @@ various pieces of functionality:
You need to enable one of the following Cargo features together with the You need to enable one of the following Cargo features together with the
`v4` feature if you're targeting `wasm32-unknown-unknown` target: `v4` feature if you're targeting `wasm32-unknown-unknown` target:
* `stdweb` - enables support for `OsRng` on `wasm32-unknown-unknown` via * `js` - enables support for randomness on
`stdweb` combined with `cargo-web` `wasm32-unknown-unknown` via [`getrandom`]
* `wasm-bindgen` - `wasm-bindgen` enables support for `OsRng` on
`wasm32-unknown-unknown` via [`wasm-bindgen`]
Alternatively, you can provide a custom `getrandom` implementation yourself 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). via [`getrandom::register_custom_getrandom`](https://docs.rs/getrandom/0.2.2/getrandom/macro.register_custom_getrandom.html).

View File

@ -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<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error>
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<crate::Uuid, D::Error>
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,
],
)
}
}

View File

@ -13,10 +13,30 @@
//! //!
//! [`Uuid`]: ../struct.Uuid.html //! [`Uuid`]: ../struct.Uuid.html
mod error; use crate::{error::*, Bytes, Uuid, Variant, Version};
pub(crate) use self::error::Error;
use crate::prelude::*; /// 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 { impl Uuid {
/// The 'nil UUID'. /// The 'nil UUID'.
@ -46,10 +66,6 @@ impl Uuid {
/// Creates a UUID from four field values. /// Creates a UUID from four field values.
/// ///
/// # Errors
///
/// This function will return an error if `d4`'s length is not 8 bytes.
///
/// # Examples /// # Examples
/// ///
/// Basic usage: /// Basic usage:
@ -57,31 +73,20 @@ impl Uuid {
/// ``` /// ```
/// use uuid::Uuid; /// use uuid::Uuid;
/// ///
/// let d1 = 0xAB3F1097u32;
/// let d2 = 0x501Eu16;
/// let d3 = 0xB736u16;
/// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
/// ///
/// let uuid = Uuid::from_fields(42, 12, 5, &d4); /// let uuid = Uuid::from_fields(d1, d2, d3, &d4);
/// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string());
/// ///
/// let expected_uuid = /// assert_eq!(
/// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); /// uuid.to_hyphenated().to_string(),
/// /// "ab3f1097-501e-b736-0c03-0938362b0809"
/// assert_eq!(expected_uuid, uuid); /// );
/// ``` /// ```
pub fn from_fields( pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Uuid {
d1: u32, Uuid::from_bytes([
d2: u16,
d3: u16,
d4: &[u8],
) -> Result<Uuid, crate::Error> {
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([
(d1 >> 24) as u8, (d1 >> 24) as u8,
(d1 >> 16) as u8, (d1 >> 16) as u8,
(d1 >> 8) as u8, (d1 >> 8) as u8,
@ -98,7 +103,7 @@ impl Uuid {
d4[5], d4[5],
d4[6], d4[6],
d4[7], d4[7],
])) ])
} }
/// Creates a UUID from four field values in little-endian order. /// Creates a UUID from four field values in little-endian order.
@ -119,28 +124,14 @@ impl Uuid {
/// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
/// ///
/// let uuid = Uuid::from_fields_le(d1, d2, d3, &d4); /// let uuid = Uuid::from_fields_le(d1, d2, d3, &d4);
/// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string());
/// ///
/// let expected_uuid = /// assert_eq!(
/// Ok(String::from("97103fab-1e50-36b7-0c03-0938362b0809")); /// uuid.to_hyphenated().to_string(),
/// /// "97103fab-1e50-36b7-0c03-0938362b0809"
/// assert_eq!(expected_uuid, uuid); /// );
/// ``` /// ```
pub fn from_fields_le( pub const fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid {
d1: u32, Uuid::from_bytes([
d2: u16,
d3: u16,
d4: &[u8],
) -> Result<Uuid, crate::Error> {
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([
d1 as u8, d1 as u8,
(d1 >> 8) as u8, (d1 >> 8) as u8,
(d1 >> 16) as u8, (d1 >> 16) as u8,
@ -157,10 +148,27 @@ impl Uuid {
d4[5], d4[5],
d4[6], d4[6],
d4[7], d4[7],
])) ])
} }
/// Creates a UUID from a 128bit value. /// 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 { pub const fn from_u128(v: u128) -> Self {
Uuid::from_bytes([ Uuid::from_bytes([
(v >> 120) as u8, (v >> 120) as u8,
@ -188,6 +196,23 @@ impl Uuid {
/// This is based on the endianness of the UUID, rather than the target /// 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 /// environment so bytes will be flipped on both big and little endian
/// machines. /// 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 { pub const fn from_u128_le(v: u128) -> Self {
Uuid::from_bytes([ Uuid::from_bytes([
v as u8, v as u8,
@ -210,6 +235,24 @@ impl Uuid {
} }
/// Creates a UUID from two 64bit values. /// 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 { pub const fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self {
Uuid::from_bytes([ Uuid::from_bytes([
(high_bits >> 56) as u8, (high_bits >> 56) as u8,
@ -242,22 +285,25 @@ impl Uuid {
/// Basic usage: /// Basic usage:
/// ///
/// ``` /// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use uuid::Uuid; /// use uuid::Uuid;
/// ///
/// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87]; /// 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::from_slice(&bytes)?;
/// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string());
/// ///
/// let expected_uuid = /// assert_eq!(
/// Ok(String::from("0436430c-2b02-624c-2032-570501212b57")); /// uuid.to_hyphenated().to_string(),
/// /// "0436430c-2b02-624c-2032-570501212b57"
/// assert_eq!(expected_uuid, uuid); /// );
/// # Ok(())
/// # }
/// ``` /// ```
/// ///
/// An incorrect number of bytes: /// An incorrect number of bytes:
/// ///
/// ``` /// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use uuid::Uuid; /// use uuid::Uuid;
/// ///
/// let bytes = [4, 54, 67, 12, 43, 2, 98, 76]; /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
@ -265,14 +311,16 @@ impl Uuid {
/// let uuid = Uuid::from_slice(&bytes); /// let uuid = Uuid::from_slice(&bytes);
/// ///
/// assert!(uuid.is_err()); /// assert!(uuid.is_err());
/// # Ok(())
/// # }
/// ``` /// ```
pub fn from_slice(b: &[u8]) -> Result<Uuid, crate::Error> { pub fn from_slice(b: &[u8]) -> Result<Uuid, Error> {
const BYTES_LEN: usize = 16; if b.len() != 16 {
return Err(ErrorKind::InvalidLength {
let len = b.len(); expected: ExpectedLength::Exact(16),
found: b.len(),
if len != BYTES_LEN { }
return crate::err(Error::new(BYTES_LEN, len)); .into());
} }
let mut bytes: Bytes = [0; 16]; let mut bytes: Bytes = [0; 16];
@ -281,32 +329,32 @@ impl Uuid {
} }
/// Creates a UUID using the supplied bytes. /// Creates a UUID using the supplied bytes.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// 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 { pub const fn from_bytes(bytes: Bytes) -> Uuid {
Uuid(bytes) Uuid(bytes)
} }
} }
/// A builder struct for creating a UUID. impl Builder {
///
/// # 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 {
/// Creates a `Builder` using the supplied bytes. /// Creates a `Builder` using the supplied bytes.
/// ///
/// # Examples /// # Examples
@ -369,68 +417,64 @@ impl crate::Builder {
/// ///
/// assert!(builder.is_err()); /// assert!(builder.is_err());
/// ``` /// ```
pub fn from_slice(b: &[u8]) -> Result<Self, crate::Error> { pub fn from_slice(b: &[u8]) -> Result<Self, Error> {
const BYTES_LEN: usize = 16; Ok(Builder(*Uuid::from_slice(b)?.as_bytes()))
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))
} }
/// Creates a `Builder` from four field values. /// Creates a `Builder` from four field values.
/// ///
/// # Errors
///
/// This function will return an error if `d4`'s length is not 8 bytes.
///
/// # Examples /// # Examples
/// ///
/// Basic usage: /// Basic usage:
/// ///
/// ``` /// ```
/// let d1 = 0xAB3F1097u32;
/// let d2 = 0x501Eu16;
/// let d3 = 0xB736u16;
/// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; /// 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(d1, d2, d3, &d4).into_uuid();
/// let uuid =
/// builder.map(|mut builder| builder.build().to_hyphenated().to_string());
/// ///
/// let expected_uuid = /// assert_eq!(
/// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); /// uuid.to_hyphenated().to_string(),
/// /// "ab3f1097-501e-b736-0c03-0938362b0809"
/// assert_eq!(expected_uuid, uuid); /// );
/// ``` /// ```
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, d1: u32,
d2: u16, d2: u16,
d3: u16, d3: u16,
d4: &[u8], d4: &[u8; 8],
) -> Result<Self, crate::Error> { ) -> Self {
Uuid::from_fields(d1, d2, d3, d4).map(|uuid| { Builder::from_bytes(*Uuid::from_fields_le(d1, d2, d3, d4).as_bytes())
let bytes = *uuid.as_bytes();
crate::Builder::from_bytes(bytes)
})
} }
/// Creates a `Builder` from a 128bit value. /// Creates a `Builder` from a 128bit value.
pub fn from_u128(v: u128) -> Self { pub const fn from_u128(v: u128) -> Self {
crate::Builder::from_bytes(*Uuid::from_u128(v).as_bytes()) Builder::from_bytes(*Uuid::from_u128(v).as_bytes())
} }
/// Creates a `Builder` with an initial [`Uuid::nil`]. /// Creates a `Builder` with an initial [`Uuid::nil`].
@ -454,21 +498,33 @@ impl crate::Builder {
} }
/// Specifies the variant of the UUID. /// Specifies the variant of the UUID.
pub fn set_variant(&mut self, v: crate::Variant) -> &mut Self { 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: Variant) -> Self {
let byte = self.0[8]; let byte = self.0[8];
self.0[8] = match v { self.0[8] = match v {
crate::Variant::NCS => byte & 0x7f, Variant::NCS => byte & 0x7f,
crate::Variant::RFC4122 => (byte & 0x3f) | 0x80, Variant::RFC4122 => (byte & 0x3f) | 0x80,
crate::Variant::Microsoft => (byte & 0x1f) | 0xc0, Variant::Microsoft => (byte & 0x1f) | 0xc0,
crate::Variant::Future => (byte & 0x1f) | 0xe0, Variant::Future => (byte & 0x1f) | 0xe0,
}; };
self self
} }
/// Specifies the version number of the UUID. /// Specifies the version number of the UUID.
pub fn set_version(&mut self, v: crate::Version) -> &mut Self { 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: Version) -> Self {
self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4);
self self
@ -495,4 +551,9 @@ impl crate::Builder {
pub fn build(&mut self) -> Uuid { pub fn build(&mut self) -> Uuid {
Uuid::from_bytes(self.0) Uuid::from_bytes(self.0)
} }
/// Convert the builder into a [`Uuid`].
pub const fn into_uuid(self) -> Uuid {
Uuid::from_bytes(self.0)
}
} }

View File

@ -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 {}
}

View File

@ -1,54 +1,140 @@
use crate::std::fmt; use crate::std::fmt;
use crate::{builder, parser};
/// A general error that can occur when working with UUIDs. /// 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)] #[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error(Inner); pub struct Error(pub(crate) ErrorKind);
pub(crate) fn err<T>(err: impl Into<Error>) -> Result<T, Error> { #[derive(Clone, Debug, Eq, Hash, PartialEq)]
Err(err.into()) 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,
},
} }
// TODO: write tests for Error /// The expected length.
// BODY: not immediately blocking, but should be covered for 1.0 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub(crate) enum ExpectedLength {
enum Inner { /// Expected any one of the given values.
/// An error occurred while handling [`Uuid`] bytes. Any(&'static [usize]),
/// /// Expected the given value.
/// See [`BytesError`] Exact(usize),
///
/// [`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),
} }
impl From<builder::Error> for Error { /// Urn prefix value.
fn from(err: builder::Error) -> Self { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
Error(Inner::Build(err)) 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<parser::Error> for Error { impl From<ErrorKind> for Error {
fn from(err: parser::Error) -> Self { fn from(kind: ErrorKind) -> Self {
Error(Inner::Parser(err)) Error(kind)
} }
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { match self.0 {
Inner::Build(ref err) => fmt::Display::fmt(&err, f), ErrorKind::InvalidCharacter {
Inner::Parser(ref err) => fmt::Display::fmt(&err, f), 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),
} }
} }
} }
@ -58,26 +144,5 @@ mod std_support {
use super::*; use super::*;
use crate::std::error; use crate::std::error;
impl error::Error for 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"),
}
}
}
} }

View File

@ -11,13 +11,49 @@
//! Adapters for various formats for UUIDs //! Adapters for various formats for UUIDs
use crate::prelude::*; use crate::{
use crate::std::{borrow::Borrow, fmt, str}; std::{borrow::Borrow, fmt, str},
Uuid, Variant,
};
#[cfg(feature = "serde")] impl std::fmt::Debug for Uuid {
pub mod compact; #[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
/// An adaptor for formatting an [`Uuid`] as a hyphenated string. 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`]. /// Takes an owned instance of the [`Uuid`].
/// ///
@ -25,7 +61,7 @@ pub mod compact;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Hyphenated(Uuid); 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`]. /// Takes a reference of the [`Uuid`].
/// ///
@ -33,7 +69,7 @@ pub struct Hyphenated(Uuid);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HyphenatedRef<'a>(&'a Uuid); 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`]. /// Takes an owned instance of the [`Uuid`].
/// ///
@ -41,7 +77,7 @@ pub struct HyphenatedRef<'a>(&'a Uuid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Simple(Uuid); 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`]. /// Takes a reference of the [`Uuid`].
/// ///
@ -49,7 +85,7 @@ pub struct Simple(Uuid);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SimpleRef<'a>(&'a Uuid); 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`]. /// Takes an owned instance of the [`Uuid`].
/// ///
@ -57,7 +93,7 @@ pub struct SimpleRef<'a>(&'a Uuid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Urn(Uuid); 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`]. /// Takes a reference of the [`Uuid`].
/// ///
@ -927,7 +963,7 @@ impl<'a> UrnRef<'a> {
} }
} }
macro_rules! impl_adapter_traits { macro_rules! impl_fmt_traits {
($($T:ident<$($a:lifetime),*>),+) => {$( ($($T:ident<$($a:lifetime),*>),+) => {$(
impl<$($a),*> fmt::Display for $T<$($a),*> { impl<$($a),*> fmt::Display for $T<$($a),*> {
#[inline] #[inline]
@ -950,11 +986,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<>) => { ($T:ident<>) => {
impl From<Uuid> for $T { impl From<Uuid> for $T {
#[inline] #[inline]
@ -1015,7 +1051,7 @@ macro_rules! impl_adapter_from {
}; };
} }
impl_adapter_traits! { impl_fmt_traits! {
Hyphenated<>, Hyphenated<>,
HyphenatedRef<'a>, HyphenatedRef<'a>,
Simple<>, Simple<>,
@ -1026,7 +1062,7 @@ impl_adapter_traits! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::prelude::*; use super::*;
#[test] #[test]
fn hyphenated_trailing() { fn hyphenated_trailing() {

View File

@ -68,11 +68,16 @@
//! //!
//! ## WebAssembly //! ## WebAssembly
//! //!
//! For WebAssembly, enable one of the following features depending //! For WebAssembly, enable the `js` feature along with `v4` for a
//! on your JavaScript interop toolchain of choice: //! source of randomness:
//! //!
//! * `stdweb` - for [`stdweb`] combined with [`cargo-web`] //! ```toml
//! * `wasm-bindgen` - for [`wasm-bindgen`] //! [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 //! ## Embedded
//! //!
@ -158,7 +163,6 @@
//! //!
//! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen //! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen
//! [`cargo-web`]: https://crates.io/crates/cargo-web //! [`cargo-web`]: https://crates.io/crates/cargo-web
//! [`stdweb`]: https://crates.io/crates/stdweb
//! [`Uuid`]: struct.Uuid.html //! [`Uuid`]: struct.Uuid.html
//! [`Uuid::new_v1`]: struct.Uuid.html#method.new_v1 //! [`Uuid::new_v1`]: struct.Uuid.html#method.new_v1
//! [`Uuid::new_v3`]: struct.Uuid.html#method.new_v3 //! [`Uuid::new_v3`]: struct.Uuid.html#method.new_v3
@ -187,9 +191,8 @@ extern crate core as std;
mod builder; mod builder;
mod error; mod error;
mod parser; mod parser;
mod prelude;
pub mod adapter; pub mod fmt;
#[cfg(feature = "v1")] #[cfg(feature = "v1")]
pub mod v1; pub mod v1;
@ -197,8 +200,6 @@ pub mod v1;
mod serde_support; mod serde_support;
#[cfg(feature = "slog")] #[cfg(feature = "slog")]
mod slog_support; mod slog_support;
#[cfg(test)]
mod test_util;
#[cfg(feature = "v3")] #[cfg(feature = "v3")]
mod v3; mod v3;
#[cfg(feature = "v4")] #[cfg(feature = "v4")]
@ -208,35 +209,9 @@ mod v5;
#[cfg(all(windows, feature = "winapi"))] #[cfg(all(windows, feature = "winapi"))]
mod winapi_support; mod winapi_support;
use crate::{ use crate::std::convert;
error::err,
std::{convert, fmt, str},
};
pub use crate::error::Error; pub use crate::{builder::Builder, 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);
/// A 128-bit (16 byte) buffer containing the ID. /// A 128-bit (16 byte) buffer containing the ID.
pub type Bytes = [u8; 16]; pub type Bytes = [u8; 16];
@ -305,15 +280,20 @@ impl Uuid {
/// ///
/// This determines the interpretation of the structure of the UUID. /// This determines the interpretation of the structure of the UUID.
/// Currently only the RFC4122 variant is generated by this module. /// 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) /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
pub const fn get_variant(&self) -> Option<Variant> { pub const fn get_variant(&self) -> Variant {
match self.as_bytes()[8] { match self.as_bytes()[8] {
x if x & 0x80 == 0x00 => Some(Variant::NCS), x if x & 0x80 == 0x00 => Variant::NCS,
x if x & 0xc0 == 0x80 => Some(Variant::RFC4122), x if x & 0xc0 == 0x80 => Variant::RFC4122,
x if x & 0xe0 == 0xc0 => Some(Variant::Microsoft), x if x & 0xe0 == 0xc0 => Variant::Microsoft,
x if x & 0xe0 == 0xe0 => Some(Variant::Future), x if x & 0xe0 == 0xe0 => Variant::Future,
_ => None, // The above match arms are actually exhaustive
// We just return `Future` here because we can't
// use `unreachable!()` in a `const fn`
_ => Variant::Future,
} }
} }
@ -399,14 +379,11 @@ impl Uuid {
| (bytes[2] as u32) << 8 | (bytes[2] as u32) << 8
| (bytes[3] as u32); | (bytes[3] as u32);
let d2 = let d2 = (bytes[4] as u16) << 8 | (bytes[5] as u16);
(bytes[4] as u16) << 8 | (bytes[5] as u16);
let d3 = let d3 = (bytes[6] as u16) << 8 | (bytes[7] as u16);
(bytes[6] as u16) << 8 | (bytes[7] as u16);
let d4: &[u8; 8] = let d4: &[u8; 8] = convert::TryInto::try_into(&bytes[8..16]).unwrap();
convert::TryInto::try_into(&bytes[8..16]).unwrap();
(d1, d2, d3, d4) (d1, d2, d3, d4)
} }
@ -442,11 +419,9 @@ impl Uuid {
| (self.as_bytes()[2] as u32) << 16 | (self.as_bytes()[2] as u32) << 16
| (self.as_bytes()[3] as u32) << 24; | (self.as_bytes()[3] as u32) << 24;
let d2 = let d2 = (self.as_bytes()[4] as u16) | (self.as_bytes()[5] as u16) << 8;
(self.as_bytes()[4] as u16) | (self.as_bytes()[5] as u16) << 8;
let d3 = let d3 = (self.as_bytes()[6] as u16) | (self.as_bytes()[7] as u16) << 8;
(self.as_bytes()[6] as u16) | (self.as_bytes()[7] as u16) << 8;
let d4: &[u8; 8] = let d4: &[u8; 8] =
convert::TryInto::try_into(&self.as_bytes()[8..16]).unwrap(); convert::TryInto::try_into(&self.as_bytes()[8..16]).unwrap();
@ -573,7 +548,7 @@ impl Uuid {
} }
/// A buffer that can be used for `encode_...` calls, that is /// 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 /// # Examples
/// ///
@ -598,53 +573,8 @@ impl Uuid {
/// "urn:uuid:00000000-0000-0000-0000-000000000000" /// "urn:uuid:00000000-0000-0000-0000-000000000000"
/// ); /// );
/// ``` /// ```
pub const fn encode_buffer() -> [u8; adapter::Urn::LENGTH] { pub const fn encode_buffer() -> [u8; fmt::Urn::LENGTH] {
[0; adapter::Urn::LENGTH] [0; fmt::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<Self, Self::Err> {
Uuid::parse_str(uuid_str)
} }
} }
@ -664,11 +594,9 @@ impl AsRef<[u8]> for Uuid {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use super::*;
prelude::*,
std::string::{String, ToString}, use crate::std::string::{String, ToString};
test_util,
};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
@ -682,11 +610,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] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_compare() { fn test_uuid_compare() {
let uuid1 = test_util::new(); let uuid1 = new();
let uuid2 = test_util::new2(); let uuid2 = new2();
assert_eq!(uuid1, uuid1); assert_eq!(uuid1, uuid1);
assert_eq!(uuid2, uuid2); assert_eq!(uuid2, uuid2);
@ -707,9 +649,9 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_display() { fn test_uuid_display() {
use super::fmt::Write; use crate::std::fmt::Write;
let uuid = test_util::new(); let uuid = new();
let s = uuid.to_string(); let s = uuid.to_string();
let mut buffer = String::new(); let mut buffer = String::new();
@ -723,10 +665,10 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_lowerhex() { fn test_uuid_lowerhex() {
use super::fmt::Write; use crate::std::fmt::Write;
let mut buffer = String::new(); let mut buffer = String::new();
let uuid = test_util::new(); let uuid = new();
check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase() check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
|| c.is_digit(10) || c.is_digit(10)
@ -737,9 +679,9 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_operator_eq() { fn test_uuid_operator_eq() {
let uuid1 = test_util::new(); let uuid1 = new();
let uuid1_dup = uuid1.clone(); let uuid1_dup = uuid1.clone();
let uuid2 = test_util::new2(); let uuid2 = new2();
assert!(uuid1 == uuid1); assert!(uuid1 == uuid1);
assert!(uuid1 == uuid1_dup); assert!(uuid1 == uuid1_dup);
@ -754,9 +696,9 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_to_string() { fn test_uuid_to_string() {
use super::fmt::Write; use crate::std::fmt::Write;
let uuid = test_util::new(); let uuid = new();
let s = uuid.to_string(); let s = uuid.to_string();
let mut buffer = String::new(); let mut buffer = String::new();
@ -770,10 +712,10 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_uuid_upperhex() { fn test_uuid_upperhex() {
use super::fmt::Write; use crate::std::fmt::Write;
let mut buffer = String::new(); let mut buffer = String::new();
let uuid = test_util::new(); let uuid = new();
check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase() check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
|| c.is_digit(10) || c.is_digit(10)
@ -784,7 +726,7 @@ mod tests {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_nil() { fn test_nil() {
let nil = Uuid::nil(); let nil = Uuid::nil();
let not_nil = test_util::new(); let not_nil = new();
let from_bytes = Uuid::from_bytes([ let from_bytes = Uuid::from_bytes([
4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87, 4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87,
]); ]);
@ -833,7 +775,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_get_variant() { fn test_get_variant() {
let uuid1 = test_util::new(); let uuid1 = new();
let uuid2 = let uuid2 =
Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
let uuid3 = let uuid3 =
@ -845,18 +787,18 @@ mod tests {
let uuid6 = let uuid6 =
Uuid::parse_str("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap(); Uuid::parse_str("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
assert_eq!(uuid1.get_variant().unwrap(), Variant::RFC4122); assert_eq!(uuid1.get_variant(), Variant::RFC4122);
assert_eq!(uuid2.get_variant().unwrap(), Variant::RFC4122); assert_eq!(uuid2.get_variant(), Variant::RFC4122);
assert_eq!(uuid3.get_variant().unwrap(), Variant::RFC4122); assert_eq!(uuid3.get_variant(), Variant::RFC4122);
assert_eq!(uuid4.get_variant().unwrap(), Variant::Microsoft); assert_eq!(uuid4.get_variant(), Variant::Microsoft);
assert_eq!(uuid5.get_variant().unwrap(), Variant::Microsoft); assert_eq!(uuid5.get_variant(), Variant::Microsoft);
assert_eq!(uuid6.get_variant().unwrap(), Variant::NCS); assert_eq!(uuid6.get_variant(), Variant::NCS);
} }
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_to_simple_string() { fn test_to_simple_string() {
let uuid1 = test_util::new(); let uuid1 = new();
let s = uuid1.to_simple().to_string(); let s = uuid1.to_simple().to_string();
assert_eq!(s.len(), 32); assert_eq!(s.len(), 32);
@ -866,7 +808,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_to_hyphenated_string() { fn test_to_hyphenated_string() {
let uuid1 = test_util::new(); let uuid1 = new();
let s = uuid1.to_hyphenated().to_string(); let s = uuid1.to_hyphenated().to_string();
assert!(s.len() == 36); assert!(s.len() == 36);
@ -879,7 +821,7 @@ mod tests {
use std::fmt::Write; use std::fmt::Write;
let mut buf = String::new(); let mut buf = String::new();
let u = test_util::new(); let u = new();
macro_rules! check { macro_rules! check {
($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => { ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
@ -909,7 +851,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_to_urn_string() { fn test_to_urn_string() {
let uuid1 = test_util::new(); let uuid1 = new();
let ss = uuid1.to_urn().to_string(); let ss = uuid1.to_urn().to_string();
let s = &ss[9..]; let s = &ss[9..];
@ -921,7 +863,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_to_simple_string_matching() { fn test_to_simple_string_matching() {
let uuid1 = test_util::new(); let uuid1 = new();
let hs = uuid1.to_hyphenated().to_string(); let hs = uuid1.to_hyphenated().to_string();
let ss = uuid1.to_simple().to_string(); let ss = uuid1.to_simple().to_string();
@ -934,7 +876,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_string_roundtrip() { fn test_string_roundtrip() {
let uuid = test_util::new(); let uuid = new();
let hs = uuid.to_hyphenated().to_string(); let hs = uuid.to_hyphenated().to_string();
let uuid_hs = Uuid::parse_str(&hs).unwrap(); let uuid_hs = Uuid::parse_str(&hs).unwrap();
@ -953,7 +895,7 @@ mod tests {
let d3: u16 = 0xc1c2; let d3: u16 = 0xc1c2;
let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; 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 expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string(); let result = u.to_simple().to_string();
@ -968,7 +910,7 @@ mod tests {
let d3: u16 = 0xc2c1; let d3: u16 = 0xc2c1;
let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; 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 expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string(); let result = u.to_simple().to_string();
@ -978,7 +920,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_as_fields() { fn test_as_fields() {
let u = test_util::new(); let u = new();
let (d1, d2, d3, d4) = u.as_fields(); let (d1, d2, d3, d4) = u.as_fields();
assert_ne!(d1, 0); assert_ne!(d1, 0);
@ -996,7 +938,7 @@ mod tests {
let d3_in: u16 = 0xc1c2; let d3_in: u16 = 0xc1c2;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; 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(); let (d1_out, d2_out, d3_out, d4_out) = u.as_fields();
assert_eq!(d1_in, d1_out); assert_eq!(d1_in, d1_out);
@ -1013,7 +955,7 @@ mod tests {
let d3_in: u16 = 0xc2c1; let d3_in: u16 = 0xc2c1;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; 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(); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
assert_eq!(d1_in, d1_out); assert_eq!(d1_in, d1_out);
@ -1030,7 +972,7 @@ mod tests {
let d3_in: u16 = 0xc1c2; let d3_in: u16 = 0xc1c2;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; 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(); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
assert_eq!(d1_in, d1_out.swap_bytes()); assert_eq!(d1_in, d1_out.swap_bytes());
@ -1153,7 +1095,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_as_bytes() { fn test_as_bytes() {
let u = test_util::new(); let u = new();
let ub = u.as_bytes(); let ub = u.as_bytes();
let ur = u.as_ref(); let ur = u.as_ref();
@ -1182,8 +1124,8 @@ mod tests {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_iterbytes_impl_for_uuid() { fn test_iterbytes_impl_for_uuid() {
let mut set = std::collections::HashSet::new(); let mut set = std::collections::HashSet::new();
let id1 = test_util::new(); let id1 = new();
let id2 = test_util::new2(); let id2 = new2();
set.insert(id1.clone()); set.insert(id1.clone());
assert!(set.contains(&id1)); assert!(set.contains(&id1));

View File

@ -13,10 +13,15 @@
//! //!
//! [`Uuid`]: ../struct.Uuid.html //! [`Uuid`]: ../struct.Uuid.html
pub(crate) mod error; use crate::{error::*, fmt, std::str, Uuid};
pub(crate) use self::error::Error;
use crate::{adapter, Uuid}; impl str::FromStr for Uuid {
type Err = Error;
fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
Uuid::parse_str(uuid_str)
}
}
/// Check if the length matches any of the given criteria lengths. /// Check if the length matches any of the given criteria lengths.
fn len_matches_any(len: usize, crits: &[usize]) -> bool { fn len_matches_any(len: usize, crits: &[usize]) -> bool {
@ -29,19 +34,6 @@ fn len_matches_any(len: usize, crits: &[usize]) -> bool {
false 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. // Accumulated length of each hyphenated group in hex digits.
const ACC_GROUP_LENS: [usize; 5] = [8, 12, 16, 20, 32]; const ACC_GROUP_LENS: [usize; 5] = [8, 12, 16, 20, 32];
@ -54,23 +46,24 @@ impl Uuid {
/// ///
/// Any of the formats generated by this module (simple, hyphenated, urn) /// Any of the formats generated by this module (simple, hyphenated, urn)
/// are supported by this parsing function. /// are supported by this parsing function.
pub fn parse_str(mut input: &str) -> Result<Uuid, crate::Error> { pub fn parse_str(mut input: &str) -> Result<Uuid, Error> {
// Ensure length is valid for any of the supported formats // Ensure length is valid for any of the supported formats
let len = input.len(); 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..]; input = &input[9..];
} else if !len_matches_any( } else if !len_matches_any(
len, len,
&[adapter::Hyphenated::LENGTH, adapter::Simple::LENGTH], &[fmt::Hyphenated::LENGTH, fmt::Simple::LENGTH],
) { ) {
return crate::err(Error::InvalidLength { return Err(ErrorKind::InvalidLength {
expected: error::ExpectedLength::Any(&[ expected: ExpectedLength::Any(&[
adapter::Hyphenated::LENGTH, fmt::Hyphenated::LENGTH,
adapter::Simple::LENGTH, fmt::Simple::LENGTH,
]), ]),
found: len, found: len,
}); }
.into());
} }
// `digit` counts only hexadecimal digits, `i_char` counts all chars. // `digit` counts only hexadecimal digits, `i_char` counts all chars.
@ -80,54 +73,51 @@ impl Uuid {
let mut buffer = [0u8; 16]; let mut buffer = [0u8; 16];
for (i_char, chr) in input.bytes().enumerate() { 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 { if group == 0 {
return crate::err(Error::InvalidLength { return Err(ErrorKind::InvalidLength {
expected: error::ExpectedLength::Any(&[ expected: ExpectedLength::Any(&[
adapter::Hyphenated::LENGTH, fmt::Hyphenated::LENGTH,
adapter::Simple::LENGTH, fmt::Simple::LENGTH,
]), ]),
found: len, found: len,
}); }
.into());
} }
return crate::err(Error::InvalidGroupCount { return Err(ErrorKind::InvalidGroupCount {
expected: error::ExpectedLength::Any(&[1, 5]), expected: ExpectedLength::Any(&[1, 5]),
found: group + 1, found: group + 1,
}); }
.into());
} }
if digit % 2 == 0 { if digit % 2 == 0 {
// First digit of the byte. // First digit of the byte.
match chr { match chr {
// Calulate upper half. // Calculate upper half.
b'0'..=b'9' => acc = chr - b'0', 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,
b'A'..=b'F' => acc = chr - b'A' + 10, b'A'..=b'F' => acc = chr - b'A' + 10,
// Found a group delimiter // Found a group delimiter
b'-' => { b'-' => {
// TODO: remove the u8 cast
// BODY: this only needed until we switch to
// ParseError
if ACC_GROUP_LENS[group] as u8 != digit { if ACC_GROUP_LENS[group] as u8 != digit {
// Calculate how many digits this group consists of // Calculate how many digits this group consists of
// in the input. // in the input.
let found = if group > 0 { 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 digit - ACC_GROUP_LENS[group - 1] as u8
} else { } else {
digit digit
}; };
return crate::err(Error::InvalidGroupLength { return Err(ErrorKind::InvalidGroupLength {
expected: error::ExpectedLength::Exact( expected: ExpectedLength::Exact(
GROUP_LENS[group], GROUP_LENS[group],
), ),
found: found as usize, found: found as usize,
group, group,
}); }
.into());
} }
// Next group, decrement digit, it is incremented again // Next group, decrement digit, it is incremented again
// at the bottom. // at the bottom.
@ -135,12 +125,13 @@ impl Uuid {
digit -= 1; digit -= 1;
} }
_ => { _ => {
return crate::err(Error::InvalidCharacter { return Err(ErrorKind::InvalidCharacter {
expected: "0123456789abcdefABCDEF-", expected: "0123456789abcdefABCDEF-",
found: input[i_char..].chars().next().unwrap(), found: input[i_char..].chars().next().unwrap(),
index: i_char, index: i_char,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}); }
.into());
} }
} }
} else { } else {
@ -153,29 +144,26 @@ impl Uuid {
b'-' => { b'-' => {
// The byte isn't complete yet. // The byte isn't complete yet.
let found = if group > 0 { 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 digit - ACC_GROUP_LENS[group - 1] as u8
} else { } else {
digit digit
}; };
return crate::err(Error::InvalidGroupLength { return Err(ErrorKind::InvalidGroupLength {
expected: error::ExpectedLength::Exact( expected: ExpectedLength::Exact(GROUP_LENS[group]),
GROUP_LENS[group],
),
found: found as usize, found: found as usize,
group, group,
}); }
.into());
} }
_ => { _ => {
return crate::err(Error::InvalidCharacter { return Err(ErrorKind::InvalidCharacter {
expected: "0123456789abcdefABCDEF-", expected: "0123456789abcdefABCDEF-",
found: input[i_char..].chars().next().unwrap(), found: input[i_char..].chars().next().unwrap(),
index: i_char, index: i_char,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}); }
.into());
} }
} }
buffer[(digit / 2) as usize] = acc; buffer[(digit / 2) as usize] = acc;
@ -184,15 +172,13 @@ impl Uuid {
} }
// Now check the last group. // 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 { if ACC_GROUP_LENS[4] as u8 != digit {
return crate::err(Error::InvalidGroupLength { return Err(ErrorKind::InvalidGroupLength {
expected: error::ExpectedLength::Exact(GROUP_LENS[4]), expected: ExpectedLength::Exact(GROUP_LENS[4]),
found: (digit as usize - ACC_GROUP_LENS[3]), found: (digit as usize - ACC_GROUP_LENS[3]),
group, group,
}); }
.into());
} }
Ok(Uuid::from_bytes(buffer)) Ok(Uuid::from_bytes(buffer))
@ -202,180 +188,164 @@ impl Uuid {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{adapter, std::string::ToString, test_util}; use crate::{fmt, std::string::ToString, tests::new};
#[test] #[test]
fn test_parse_uuid_v4() { fn test_parse_uuid_v4() {
const EXPECTED_UUID_LENGTHS: error::ExpectedLength = const EXPECTED_UUID_LENGTHS: ExpectedLength = ExpectedLength::Any(&[
error::ExpectedLength::Any(&[ fmt::Hyphenated::LENGTH,
adapter::Hyphenated::LENGTH, fmt::Simple::LENGTH,
adapter::Simple::LENGTH, ]);
]);
const EXPECTED_GROUP_COUNTS: error::ExpectedLength = const EXPECTED_GROUP_COUNTS: ExpectedLength =
error::ExpectedLength::Any(&[1, 5]); ExpectedLength::Any(&[1, 5]);
const EXPECTED_CHARS: &'static str = "0123456789abcdefABCDEF-"; const EXPECTED_CHARS: &'static str = "0123456789abcdefABCDEF-";
// Invalid // Invalid
assert_eq!( assert_eq!(
Uuid::parse_str("").map_err(crate::Error::expect_parser), Uuid::parse_str(""),
Err(Error::InvalidLength { Err(Error(ErrorKind::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 0, found: 0,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("!").map_err(crate::Error::expect_parser), Uuid::parse_str("!"),
Err(Error::InvalidLength { Err(Error(ErrorKind::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 1 found: 1
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45") Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 37, found: 37,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 35 found: 35
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidCharacter {
Err(Error::InvalidCharacter {
expected: EXPECTED_CHARS, expected: EXPECTED_CHARS,
found: 'G', found: 'G',
index: 20, index: 20,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupCount {
Err(Error::InvalidGroupCount {
expected: EXPECTED_GROUP_COUNTS, expected: EXPECTED_GROUP_COUNTS,
found: 2 found: 2
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupCount {
Err(Error::InvalidGroupCount {
expected: EXPECTED_GROUP_COUNTS, expected: EXPECTED_GROUP_COUNTS,
found: 3, found: 3,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupCount {
Err(Error::InvalidGroupCount {
expected: EXPECTED_GROUP_COUNTS, expected: EXPECTED_GROUP_COUNTS,
found: 4, found: 4,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa") Uuid::parse_str("F9168C5E-CEB2-4faa"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 18, found: 18,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidCharacter {
Err(Error::InvalidCharacter {
expected: EXPECTED_CHARS, expected: EXPECTED_CHARS,
found: 'X', found: 'X',
index: 18, index: 18,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4") Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupLength {
Err(Error::InvalidGroupLength { expected: ExpectedLength::Exact(4),
expected: error::ExpectedLength::Exact(4),
found: 3, found: 3,
group: 1, group: 1,
}) }))
); );
// (group, found, expecting) // (group, found, expecting)
// //
assert_eq!( assert_eq!(
Uuid::parse_str("01020304-1112-2122-3132-41424344") Uuid::parse_str("01020304-1112-2122-3132-41424344"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupLength {
Err(Error::InvalidGroupLength { expected: ExpectedLength::Exact(12),
expected: error::ExpectedLength::Exact(12),
found: 8, found: 8,
group: 4, group: 4,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 31, found: 31,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88") Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 33, found: 33,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8") Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 33, found: 33,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8") Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidCharacter {
Err(Error::InvalidCharacter {
expected: EXPECTED_CHARS, expected: EXPECTED_CHARS,
found: '%', found: '%',
index: 15, index: 15,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("231231212212423424324323477343246663") Uuid::parse_str("231231212212423424324323477343246663"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 36, found: 36,
}) }))
); );
// Valid // Valid
@ -401,47 +371,43 @@ mod tests {
); );
// Round-trip // Round-trip
let uuid_orig = test_util::new(); let uuid_orig = new();
let orig_str = uuid_orig.to_string(); let orig_str = uuid_orig.to_string();
let uuid_out = Uuid::parse_str(&orig_str).unwrap(); let uuid_out = Uuid::parse_str(&orig_str).unwrap();
assert_eq!(uuid_orig, uuid_out); assert_eq!(uuid_orig, uuid_out);
// Test error reporting // Test error reporting
assert_eq!( assert_eq!(
Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidLength {
Err(Error::InvalidLength {
expected: EXPECTED_UUID_LENGTHS, expected: EXPECTED_UUID_LENGTHS,
found: 31, found: 31,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd") Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidCharacter {
Err(Error::InvalidCharacter {
expected: EXPECTED_CHARS, expected: EXPECTED_CHARS,
found: 'X', found: 'X',
index: 6, index: 6,
urn: error::UrnPrefix::Optional, urn: UrnPrefix::Optional,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c") Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupLength {
Err(Error::InvalidGroupLength { expected: ExpectedLength::Exact(8),
expected: error::ExpectedLength::Exact(8),
found: 6, found: 6,
group: 0, group: 0,
}) }))
); );
assert_eq!( assert_eq!(
Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4") Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"),
.map_err(crate::Error::expect_parser), Err(Error(ErrorKind::InvalidGroupLength {
Err(Error::InvalidGroupLength { expected: ExpectedLength::Exact(4),
expected: error::ExpectedLength::Exact(4),
found: 5, found: 5,
group: 3, group: 3,
}) }))
); );
} }
} }

View File

@ -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 {}
}

View File

@ -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 <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.
//! 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};

View File

@ -9,8 +9,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::prelude::*; use crate::{std::fmt, Uuid};
use core::fmt;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for Uuid { impl Serialize for Uuid {
@ -22,7 +21,7 @@ impl Serialize for Uuid {
serializer serializer
.serialize_str(self.to_hyphenated().encode_lower(&mut [0; 36])) .serialize_str(self.to_hyphenated().encode_lower(&mut [0; 36]))
} else { } else {
serializer.serialize_bytes(self.as_bytes()) self.as_bytes().serialize(serializer)
} }
} }
} }
@ -65,36 +64,18 @@ impl<'de> Deserialize<'de> for Uuid {
deserializer.deserialize_str(UuidStringVisitor) deserializer.deserialize_str(UuidStringVisitor)
} else { } else {
struct UuidBytesVisitor; let bytes: [u8; 16] = Deserialize::deserialize(deserializer)?;
impl<'vi> de::Visitor<'vi> for UuidBytesVisitor { Ok(Uuid::from_bytes(bytes))
type Value = Uuid;
fn expecting(
&self,
formatter: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(formatter, "bytes")
}
fn visit_bytes<E: de::Error>(
self,
value: &[u8],
) -> Result<Uuid, E> {
Uuid::from_slice(value).map_err(de_error)
}
}
deserializer.deserialize_bytes(UuidBytesVisitor)
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod serde_tests { mod serde_tests {
use serde_test::{Compact, Configure, Readable, Token}; use super::*;
use crate::prelude::*; use serde_test::{Compact, Configure, Readable, Token};
#[test] #[test]
fn test_serialize_readable() { fn test_serialize_readable() {
@ -107,7 +88,29 @@ mod serde_tests {
fn test_serialize_compact() { fn test_serialize_compact() {
let uuid_bytes = b"F9168C5E-CEB2-4F"; let uuid_bytes = b"F9168C5E-CEB2-4F";
let u = Uuid::from_slice(uuid_bytes).unwrap(); 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] #[test]
@ -119,7 +122,7 @@ mod serde_tests {
serde_test::assert_de_tokens_error::<Compact<Uuid>>( serde_test::assert_de_tokens_error::<Compact<Uuid>>(
&[Token::Bytes(b"hello_world")], &[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",
); );
} }
} }

View File

@ -9,7 +9,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::prelude::*; use crate::Uuid;
impl slog::Value for Uuid { impl slog::Value for Uuid {
fn serialize( fn serialize(
@ -24,15 +24,14 @@ impl slog::Value for Uuid {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests::new;
use slog::{self, crit, Drain};
#[test] #[test]
fn test_slog_kv() { 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 root = slog::Logger::root(slog::Discard.fuse(), slog::o!());
let u1 = test_util::new(); let u1 = new();
crit!(root, "test"; "u1" => u1); crit!(root, "test"; "u1" => u1);
} }
} }

View File

@ -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 <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.
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,
])
}

View File

@ -2,7 +2,8 @@
//! //!
//! Note that you need feature `v1` in order to use these features. //! Note that you need feature `v1` in order to use these features.
use crate::prelude::*; use crate::{Uuid, Version};
use atomic::Atomic; use atomic::Atomic;
/// The number of 100 ns ticks between the UUID epoch /// The number of 100 ns ticks between the UUID epoch
@ -164,7 +165,7 @@ impl Uuid {
/// ///
/// let context = Context::new(42); /// let context = Context::new(42);
/// let ts = Timestamp::from_unix(&context, 1497624119, 1234); /// 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!( /// assert_eq!(
/// uuid.to_hyphenated().to_string(), /// uuid.to_hyphenated().to_string(),
@ -180,7 +181,7 @@ impl Uuid {
/// ///
/// let context = Context::new(42); /// let context = Context::new(42);
/// let ts = Timestamp::from_rfc4122(1497624119, 0); /// 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!( /// assert_eq!(
/// uuid.to_hyphenated().to_string(), /// uuid.to_hyphenated().to_string(),
@ -191,14 +192,7 @@ impl Uuid {
/// [`Timestamp`]: v1/struct.Timestamp.html /// [`Timestamp`]: v1/struct.Timestamp.html
/// [`ClockSequence`]: v1/struct.ClockSequence.html /// [`ClockSequence`]: v1/struct.ClockSequence.html
/// [`Context`]: v1/struct.Context.html /// [`Context`]: v1/struct.Context.html
pub fn new_v1(ts: Timestamp, node_id: &[u8]) -> Result<Self, crate::Error> { pub const fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
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));
}
let time_low = (ts.ticks & 0xFFFF_FFFF) as u32; let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16; let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
let time_high_and_version = let time_high_and_version =
@ -206,12 +200,14 @@ impl Uuid {
let mut d4 = [0; 8]; let mut d4 = [0; 8];
{ d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80; d4[1] = (ts.counter & 0xFF) as u8;
d4[1] = (ts.counter & 0xFF) as u8; d4[2] = node_id[0];
} d4[3] = node_id[1];
d4[4] = node_id[2];
d4[2..].copy_from_slice(node_id); 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) Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
} }
@ -229,28 +225,25 @@ impl Uuid {
/// value into more commonly-used formats, such as a unix timestamp. /// value into more commonly-used formats, such as a unix timestamp.
/// ///
/// [`Timestamp`]: v1/struct.Timestamp.html /// [`Timestamp`]: v1/struct.Timestamp.html
pub fn to_timestamp(&self) -> Option<Timestamp> { pub const fn to_timestamp(&self) -> Option<Timestamp> {
if self match self.get_version() {
.get_version() Some(Version::Mac) => {
.map(|v| v != Version::Mac) let ticks: u64 = ((self.as_bytes()[6] & 0x0F) as u64) << 56
.unwrap_or(true) | ((self.as_bytes()[7]) as u64) << 48
{ | ((self.as_bytes()[4]) as u64) << 40
return None; | ((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))
} }
} }
@ -283,7 +276,7 @@ mod tests {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
use crate::std::string::ToString; use crate::{std::string::ToString, Variant};
#[test] #[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
@ -297,11 +290,10 @@ mod tests {
let uuid = Uuid::new_v1( let uuid = Uuid::new_v1(
Timestamp::from_unix(&context, time, time_fraction), Timestamp::from_unix(&context, time, time_fraction),
&node, &node,
) );
.unwrap();
assert_eq!(uuid.get_version(), Some(Version::Mac)); 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!( assert_eq!(
uuid.to_hyphenated().to_string(), uuid.to_hyphenated().to_string(),
"20616934-4ba2-11e7-8000-010203040506" "20616934-4ba2-11e7-8000-010203040506"
@ -317,8 +309,7 @@ mod tests {
let uuid2 = Uuid::new_v1( let uuid2 = Uuid::new_v1(
Timestamp::from_unix(&context, time, time_fraction), Timestamp::from_unix(&context, time, time_fraction),
&node, &node,
) );
.unwrap();
assert_eq!( assert_eq!(
uuid2.to_hyphenated().to_string(), uuid2.to_hyphenated().to_string(),

View File

@ -1,4 +1,5 @@
use crate::prelude::*; use crate::{Uuid, Variant, Version};
use md5::{Digest, Md5}; use md5::{Digest, Md5};
impl Uuid { impl Uuid {
@ -136,8 +137,8 @@ mod tests {
fn test_new() { fn test_new() {
for &(ref ns, ref name, _) in FIXTURE { for &(ref ns, ref name, _) in FIXTURE {
let uuid = Uuid::new_v3(*ns, name.as_bytes()); let uuid = Uuid::new_v3(*ns, name.as_bytes());
assert_eq!(uuid.get_version().unwrap(), Version::Md5); assert_eq!(uuid.get_version(), Some(Version::Md5));
assert_eq!(uuid.get_variant().unwrap(), Variant::RFC4122); assert_eq!(uuid.get_variant(), Variant::RFC4122);
} }
} }

View File

@ -1,4 +1,4 @@
use crate::prelude::*; use crate::{Uuid, Variant, Version};
impl Uuid { impl Uuid {
/// Creates a random UUID. /// Creates a random UUID.
@ -40,7 +40,7 @@ impl Uuid {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::prelude::*; use super::*;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
@ -51,7 +51,7 @@ mod tests {
let uuid = Uuid::new_v4(); let uuid = Uuid::new_v4();
assert_eq!(uuid.get_version(), Some(Version::Random)); assert_eq!(uuid.get_version(), Some(Version::Random));
assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); assert_eq!(uuid.get_variant(), Variant::RFC4122);
} }
#[test] #[test]

View File

@ -1,4 +1,5 @@
use crate::prelude::*; use crate::{Uuid, Variant, Version};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
impl Uuid { impl Uuid {
@ -156,8 +157,8 @@ mod tests {
for &(ref ns, ref name, ref u) in FIXTURE { for &(ref ns, ref name, ref u) in FIXTURE {
let uuid = Uuid::new_v5(*ns, name.as_bytes()); 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_version(), Some(Version::Sha1));
assert_eq!(uuid.get_variant(), Variant::RFC4122);
assert_eq!(Ok(uuid), u.parse()); assert_eq!(Ok(uuid), u.parse());
} }
} }

View File

@ -1,4 +1,5 @@
use crate::prelude::*; use crate::Uuid;
use winapi::shared::guiddef; use winapi::shared::guiddef;
#[cfg(feature = "guid")] #[cfg(feature = "guid")]
@ -6,15 +7,13 @@ impl Uuid {
/// Converts a little endian winapi `GUID` into a [`Uuid`] /// Converts a little endian winapi `GUID` into a [`Uuid`]
/// ///
/// [`Uuid`]: ../struct.Uuid.html /// [`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( Uuid::from_fields_le(
guid.Data1 as u32, guid.Data1 as u32,
guid.Data2 as u16, guid.Data2 as u16,
guid.Data3 as u16, guid.Data3 as u16,
&(guid.Data4 as [u8; 8]), &(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` /// Converts a [`Uuid`] into a little endian winapi `GUID`