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

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]
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]
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]
default-features = false
optional = true
version = "1.0.56"
# Private
[dependencies.sha-1]
default-features = false
optional = true
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]
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 +118,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"

View File

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

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
mod error;
pub(crate) use self::error::Error;
use crate::{error::*, Bytes, Uuid, Variant, Version};
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 {
/// The 'nil UUID'.
@ -46,10 +66,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 +73,20 @@ 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 uuid = Uuid::from_fields(d1, d2, d3, &d4);
///
/// 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 fn from_fields(
d1: u32,
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([
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,
(d1 >> 8) as u8,
@ -98,7 +103,7 @@ impl Uuid {
d4[5],
d4[6],
d4[7],
]))
])
}
/// 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 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(
d1: u32,
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([
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,
(d1 >> 16) as u8,
@ -157,10 +148,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 +196,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 +235,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 +285,25 @@ impl Uuid {
/// 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_slice(&bytes);
/// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string());
/// let uuid = Uuid::from_slice(&bytes)?;
///
/// let expected_uuid =
/// Ok(String::from("0436430c-2b02-624c-2032-570501212b57"));
///
/// 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<dyn std::error::Error>> {
/// use uuid::Uuid;
///
/// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
@ -265,14 +311,16 @@ impl Uuid {
/// let uuid = Uuid::from_slice(&bytes);
///
/// assert!(uuid.is_err());
/// # Ok(())
/// # }
/// ```
pub fn from_slice(b: &[u8]) -> Result<Uuid, crate::Error> {
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<Uuid, Error> {
if b.len() != 16 {
return Err(ErrorKind::InvalidLength {
expected: ExpectedLength::Exact(16),
found: b.len(),
}
.into());
}
let mut bytes: Bytes = [0; 16];
@ -281,32 +329,32 @@ impl Uuid {
}
/// 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 {
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
@ -369,68 +417,64 @@ impl crate::Builder {
///
/// assert!(builder.is_err());
/// ```
pub fn from_slice(b: &[u8]) -> Result<Self, crate::Error> {
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<Self, Error> {
Ok(Builder(*Uuid::from_slice(b)?.as_bytes()))
}
/// 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<Self, crate::Error> {
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`].
@ -454,21 +498,33 @@ impl crate::Builder {
}
/// 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];
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 {
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
@ -495,4 +551,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)
}
}

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::{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<T>(err: impl Into<Error>) -> Result<T, Error> {
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,
},
}
// 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.
///
/// 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),
/// 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<builder::Error> 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<parser::Error> for Error {
fn from(err: parser::Error) -> Self {
Error(Inner::Parser(err))
impl From<ErrorKind> 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),
}
}
}
@ -58,26 +144,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 {}
}

View File

@ -11,13 +11,49 @@
//! 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,
};
#[cfg(feature = "serde")]
pub mod compact;
impl std::fmt::Debug for Uuid {
#[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`].
///
@ -25,7 +61,7 @@ pub mod compact;
#[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`].
///
@ -33,7 +69,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`].
///
@ -41,7 +77,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`].
///
@ -49,7 +85,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`].
///
@ -57,7 +93,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`].
///
@ -927,7 +963,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]
@ -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<>) => {
impl From<Uuid> for $T {
#[inline]
@ -1015,7 +1051,7 @@ macro_rules! impl_adapter_from {
};
}
impl_adapter_traits! {
impl_fmt_traits! {
Hyphenated<>,
HyphenatedRef<'a>,
Simple<>,
@ -1026,7 +1062,7 @@ impl_adapter_traits! {
#[cfg(test)]
mod tests {
use crate::prelude::*;
use super::*;
#[test]
fn hyphenated_trailing() {

View File

@ -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
@ -187,9 +191,8 @@ extern crate core as std;
mod builder;
mod error;
mod parser;
mod prelude;
pub mod adapter;
pub mod fmt;
#[cfg(feature = "v1")]
pub mod v1;
@ -197,8 +200,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")]
@ -208,35 +209,9 @@ mod v5;
#[cfg(all(windows, feature = "winapi"))]
mod winapi_support;
use crate::{
error::err,
std::{convert, fmt, str},
};
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];
@ -305,15 +280,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<Variant> {
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,
}
}
@ -399,14 +379,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)
}
@ -442,11 +419,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();
@ -573,7 +548,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
///
@ -598,53 +573,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<Self, Self::Err> {
Uuid::parse_str(uuid_str)
pub const fn encode_buffer() -> [u8; fmt::Urn::LENGTH] {
[0; fmt::Urn::LENGTH]
}
}
@ -664,11 +594,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::*;
@ -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]
#[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);
@ -707,9 +649,9 @@ 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 uuid = new();
let s = uuid.to_string();
let mut buffer = String::new();
@ -723,10 +665,10 @@ 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();
let uuid = new();
check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
|| c.is_digit(10)
@ -737,9 +679,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);
@ -754,9 +696,9 @@ 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 uuid = new();
let s = uuid.to_string();
let mut buffer = String::new();
@ -770,10 +712,10 @@ 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();
let uuid = new();
check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
|| c.is_digit(10)
@ -784,7 +726,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,
]);
@ -833,7 +775,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 =
@ -845,18 +787,18 @@ 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]
#[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);
@ -866,7 +808,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);
@ -879,7 +821,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) => {
@ -909,7 +851,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..];
@ -921,7 +863,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();
@ -934,7 +876,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();
@ -953,7 +895,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 +910,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();
@ -978,7 +920,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);
@ -996,7 +938,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 +955,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 +972,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());
@ -1153,7 +1095,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();
@ -1182,8 +1124,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));

View File

@ -13,10 +13,15 @@
//!
//! [`Uuid`]: ../struct.Uuid.html
pub(crate) mod error;
pub(crate) use self::error::Error;
use crate::{error::*, fmt, std::str, Uuid};
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.
fn len_matches_any(len: usize, crits: &[usize]) -> bool {
@ -29,19 +34,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];
@ -54,23 +46,24 @@ 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<Uuid, crate::Error> {
pub fn parse_str(mut input: &str) -> Result<Uuid, Error> {
// 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,
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.
@ -80,54 +73,51 @@ 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,
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.
@ -135,12 +125,13 @@ 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 {
@ -153,29 +144,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(
GROUP_LENS[group],
),
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;
@ -184,15 +172,13 @@ 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))
@ -202,180 +188,164 @@ impl Uuid {
#[cfg(test)]
mod tests {
use super::*;
use crate::{adapter, std::string::ToString, test_util};
use crate::{fmt, std::string::ToString, tests::new};
#[test]
fn test_parse_uuid_v4() {
const EXPECTED_UUID_LENGTHS: error::ExpectedLength =
error::ExpectedLength::Any(&[
adapter::Hyphenated::LENGTH,
adapter::Simple::LENGTH,
]);
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
@ -401,47 +371,43 @@ 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);
// 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,
})
}))
);
}
}

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
// 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 {
@ -22,7 +21,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,36 +64,18 @@ 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<E: de::Error>(
self,
value: &[u8],
) -> Result<Uuid, E> {
Uuid::from_slice(value).map_err(de_error)
}
}
deserializer.deserialize_bytes(UuidBytesVisitor)
Ok(Uuid::from_bytes(bytes))
}
}
}
#[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() {
@ -107,7 +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(), &[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 +122,7 @@ mod serde_tests {
serde_test::assert_de_tokens_error::<Compact<Uuid>>(
&[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
// 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);
}
}

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.
use crate::prelude::*;
use crate::{Uuid, Version};
use atomic::Atomic;
/// The number of 100 ns ticks between the UUID epoch
@ -164,7 +165,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(),
@ -180,7 +181,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,14 +192,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<Self, crate::Error> {
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 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 =
@ -206,12 +200,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)
}
@ -229,28 +225,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<Timestamp> {
if self
.get_version()
.map(|v| v != Version::Mac)
.unwrap_or(true)
{
return None;
pub const fn to_timestamp(&self) -> Option<Timestamp> {
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))
}
}
@ -283,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)]
@ -297,11 +290,10 @@ 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));
assert_eq!(uuid.get_variant(), Variant::RFC4122);
assert_eq!(
uuid.to_hyphenated().to_string(),
"20616934-4ba2-11e7-8000-010203040506"
@ -317,8 +309,7 @@ mod tests {
let uuid2 = Uuid::new_v1(
Timestamp::from_unix(&context, time, time_fraction),
&node,
)
.unwrap();
);
assert_eq!(
uuid2.to_hyphenated().to_string(),

View File

@ -1,4 +1,5 @@
use crate::prelude::*;
use crate::{Uuid, Variant, Version};
use md5::{Digest, Md5};
impl Uuid {
@ -136,8 +137,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);
}
}

View File

@ -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::*;
@ -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]

View File

@ -1,4 +1,5 @@
use crate::prelude::*;
use crate::{Uuid, Variant, Version};
use sha1::{Digest, Sha1};
impl Uuid {
@ -156,8 +157,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());
}
}

View File

@ -1,4 +1,5 @@
use crate::prelude::*;
use crate::Uuid;
use winapi::shared::guiddef;
#[cfg(feature = "guid")]
@ -6,15 +7,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`