#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "const_fn", feature(const_fn))]
#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs
)]
#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://docs.rs/uuid/0.7.4"
)]
#[cfg(feature = "byteorder")]
extern crate byteorder;
#[cfg(feature = "std")]
extern crate core;
#[cfg(feature = "md5")]
extern crate md5;
#[cfg(feature = "rand")]
extern crate rand;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(feature = "serde", test))]
extern crate serde_test;
#[cfg(all(feature = "serde", test))]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "sha1")]
extern crate sha1;
#[cfg(feature = "slog")]
#[cfg_attr(test, macro_use)]
extern crate slog;
#[cfg(feature = "winapi")]
extern crate winapi;
pub mod adapter;
pub mod builder;
pub mod parser;
pub mod prelude;
#[cfg(feature = "v1")]
pub mod v1;
pub use builder::Builder;
mod core_support;
#[cfg(feature = "serde")]
mod serde_support;
#[cfg(feature = "slog")]
mod slog_support;
#[cfg(feature = "std")]
mod std_support;
#[cfg(test)]
mod test_util;
#[cfg(feature = "u128")]
mod u128_support;
#[cfg(all(
    feature = "v3",
    any(
        not(target_arch = "wasm32"),
        all(
            target_arch = "wasm32",
            any(feature = "stdweb", feature = "wasm-bindgen")
        )
    )
))]
mod v3;
#[cfg(all(
    feature = "v4",
    any(
        not(target_arch = "wasm32"),
        all(
            target_arch = "wasm32",
            any(feature = "stdweb", feature = "wasm-bindgen")
        )
    )
))]
mod v4;
#[cfg(all(
    feature = "v5",
    any(
        not(target_arch = "wasm32"),
        all(
            target_arch = "wasm32",
            any(feature = "stdweb", feature = "wasm-bindgen")
        )
    )
))]
mod v5;
#[cfg(all(windows, feature = "winapi"))]
mod winapi_support;
pub type Bytes = [u8; 16];
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BytesError {
    expected: usize,
    found: usize,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Error {
    
    
    
    
    
    
    Bytes(BytesError),
    
    
    
    
    
    
    Parse(parser::ParseError),
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(C)]
pub enum Version {
    
    
    
    Nil = 0,
    
    Mac,
    
    Dce,
    
    Md5,
    
    Random,
    
    Sha1,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub enum Variant {
    
    NCS = 0,
    
    RFC4122,
    
    Microsoft,
    
    Future,
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Uuid(Bytes);
impl BytesError {
    
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn expected(&self) -> usize {
        self.expected
    }
    
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn expected(&self) -> usize {
        self.expected
    }
    
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn found(&self) -> usize {
        self.found
    }
    
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn found(&self) -> usize {
        self.found
    }
    
    
    
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn new(expected: usize, found: usize) -> Self {
        BytesError { expected, found }
    }
    
    
    
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn new(expected: usize, found: usize) -> Self {
        BytesError { expected, found }
    }
}
impl Uuid {
    
    
    
    pub const NAMESPACE_DNS: Self = Uuid([
        0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
        0x4f, 0xd4, 0x30, 0xc8,
    ]);
    
    
    
    pub const NAMESPACE_OID: Self = Uuid([
        0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
        0x4f, 0xd4, 0x30, 0xc8,
    ]);
    
    
    
    pub const NAMESPACE_URL: Self = Uuid([
        0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
        0x4f, 0xd4, 0x30, 0xc8,
    ]);
    
    
    
    pub const NAMESPACE_X500: Self = Uuid([
        0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
        0x4f, 0xd4, 0x30, 0xc8,
    ]);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[cfg(feature = "const_fn")]
    pub const fn nil() -> Self {
        Uuid::from_bytes([0; 16])
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[cfg(not(feature = "const_fn"))]
    pub fn nil() -> Uuid {
        Uuid::from_bytes([0; 16])
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn from_fields(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Uuid, BytesError> {
        const D4_LEN: usize = 8;
        let len = d4.len();
        if len != D4_LEN {
            return Err(BytesError::new(D4_LEN, len));
        }
        Ok(Uuid::from_bytes([
            (d1 >> 24) as u8,
            (d1 >> 16) as u8,
            (d1 >> 8) as u8,
            d1 as u8,
            (d2 >> 8) as u8,
            d2 as u8,
            (d3 >> 8) as u8,
            d3 as u8,
            d4[0],
            d4[1],
            d4[2],
            d4[3],
            d4[4],
            d4[5],
            d4[6],
            d4[7],
        ]))
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn from_fields_le(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Uuid, BytesError> {
        const D4_LEN: usize = 8;
        let len = d4.len();
        if len != D4_LEN {
            return Err(BytesError::new(D4_LEN, len));
        }
        Ok(Uuid::from_bytes([
            d1 as u8,
            (d1 >> 8) as u8,
            (d1 >> 16) as u8,
            (d1 >> 24) as u8,
            (d2) as u8,
            (d2 >> 8) as u8,
            d3 as u8,
            (d3 >> 8) as u8,
            d4[0],
            d4[1],
            d4[2],
            d4[3],
            d4[4],
            d4[5],
            d4[6],
            d4[7],
        ]))
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn from_slice(b: &[u8]) -> Result<Uuid, BytesError> {
        const BYTES_LEN: usize = 16;
        let len = b.len();
        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }
        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Uuid::from_bytes(bytes))
    }
    
    #[cfg(not(feature = "const_fn"))]
    pub fn from_bytes(bytes: Bytes) -> Uuid {
        Uuid(bytes)
    }
    
    #[cfg(feature = "const_fn")]
    pub const fn from_bytes(bytes: Bytes) -> Uuid {
        Uuid(bytes)
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #[deprecated(
        since = "0.7.2",
        note = "please use the `uuid::Builder` instead to set the variant and version"
    )]
    pub fn from_random_bytes(bytes: Bytes) -> Uuid {
        let mut uuid = Uuid::from_bytes(bytes);
        uuid.set_variant(Variant::RFC4122);
        uuid.set_version(Version::Random);
        uuid
    }
    
    fn set_variant(&mut self, v: Variant) {
        
        self.0[8] = match v {
            Variant::NCS => self.as_bytes()[8] & 0x7f, 
            Variant::RFC4122 => (self.as_bytes()[8] & 0x3f) | 0x80, 
            Variant::Microsoft => (self.as_bytes()[8] & 0x1f) | 0xc0, 
            Variant::Future => (self.as_bytes()[8] & 0x1f) | 0xe0, 
        }
    }
    
    
    
    
    
    
    pub fn get_variant(&self) -> Option<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,
        }
    }
    
    fn set_version(&mut self, v: Version) {
        self.0[6] = (self.as_bytes()[6] & 0xF) | ((v as u8) << 4);
    }
    
    
    
    
    
    
    
    
    
    
    
    pub fn get_version_num(&self) -> usize {
        (self.as_bytes()[6] >> 4) as usize
    }
    
    
    
    pub fn get_version(&self) -> Option<Version> {
        let v = self.as_bytes()[6] >> 4;
        match v {
            0 if self.is_nil() => Some(Version::Nil),
            1 => Some(Version::Mac),
            2 => Some(Version::Dce),
            3 => Some(Version::Md5),
            4 => Some(Version::Random),
            5 => Some(Version::Sha1),
            _ => None,
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
        let d1 = u32::from(self.as_bytes()[0]) << 24
            | u32::from(self.as_bytes()[1]) << 16
            | u32::from(self.as_bytes()[2]) << 8
            | u32::from(self.as_bytes()[3]);
        let d2 =
            u16::from(self.as_bytes()[4]) << 8 | u16::from(self.as_bytes()[5]);
        let d3 =
            u16::from(self.as_bytes()[6]) << 8 | u16::from(self.as_bytes()[7]);
        let d4: &[u8; 8] =
            unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) };
        (d1, d2, d3, d4)
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn to_fields_le(&self) -> (u32, u16, u16, &[u8; 8]) {
        let d1 = u32::from(self.as_bytes()[0])
            | u32::from(self.as_bytes()[1]) << 8
            | u32::from(self.as_bytes()[2]) << 16
            | u32::from(self.as_bytes()[3]) << 24;
        let d2 =
            u16::from(self.as_bytes()[4]) | u16::from(self.as_bytes()[5]) << 8;
        let d3 =
            u16::from(self.as_bytes()[6]) | u16::from(self.as_bytes()[7]) << 8;
        let d4: &[u8; 8] =
            unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) };
        (d1, d2, d3, d4)
    }
    
    
    #[cfg(feature = "const_fn")]
    pub const fn as_bytes(&self) -> &Bytes {
        &self.0
    }
    
    
    #[cfg(not(feature = "const_fn"))]
    pub fn as_bytes(&self) -> &Bytes {
        &self.0
    }
    
    
    
    pub fn to_timestamp(&self) -> Option<(u64, u16)> {
        if self
            .get_version()
            .map(|v| v != Version::Mac)
            .unwrap_or(true)
        {
            return None;
        }
        let ts: 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 count: u16 = u16::from(self.as_bytes()[8] & 0x3F) << 8
            | u16::from(self.as_bytes()[9]);
        Some((ts, count))
    }
    
    
    
    
    
    pub fn parse_str(mut input: &str) -> Result<Uuid, parser::ParseError> {
        
        let len = input.len();
        if len == adapter::Urn::LENGTH && input.starts_with("urn:uuid:") {
            input = &input[9..];
        } else if !parser::len_matches_any(
            len,
            &[adapter::Hyphenated::LENGTH, adapter::Simple::LENGTH],
        ) {
            return Err(parser::ParseError::InvalidLength {
                expected: parser::Expected::Any(&[
                    adapter::Hyphenated::LENGTH,
                    adapter::Simple::LENGTH,
                ]),
                found: len,
            });
        }
        
        let mut digit = 0;
        let mut group = 0;
        let mut acc = 0;
        let mut buffer = [0u8; 16];
        for (i_char, chr) in input.bytes().enumerate() {
            if digit as usize >= adapter::Simple::LENGTH && group != 4 {
                if group == 0 {
                    return Err(parser::ParseError::InvalidLength {
                        expected: parser::Expected::Any(&[
                            adapter::Hyphenated::LENGTH,
                            adapter::Simple::LENGTH,
                        ]),
                        found: len,
                    });
                }
                return Err(parser::ParseError::InvalidGroupCount {
                    expected: parser::Expected::Any(&[1, 5]),
                    found: group + 1,
                });
            }
            if digit % 2 == 0 {
                
                match chr {
                    
                    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'-' => {
                        
                        
                        
                        if parser::ACC_GROUP_LENS[group] as u8 != digit {
                            
                            
                            let found = if group > 0 {
                                
                                
                                
                                digit - parser::ACC_GROUP_LENS[group - 1] as u8
                            } else {
                                digit
                            };
                            return Err(
                                parser::ParseError::InvalidGroupLength {
                                    expected: parser::Expected::Exact(
                                        parser::GROUP_LENS[group],
                                    ),
                                    found: found as usize,
                                    group,
                                },
                            );
                        }
                        
                        
                        group += 1;
                        digit -= 1;
                    }
                    _ => {
                        return Err(parser::ParseError::InvalidCharacter {
                            expected: "0123456789abcdefABCDEF-",
                            found: input[i_char..].chars().next().unwrap(),
                            index: i_char,
                        });
                    }
                }
            } else {
                
                acc *= 16;
                match chr {
                    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'-' => {
                        
                        let found = if group > 0 {
                            
                            
                            
                            digit - parser::ACC_GROUP_LENS[group - 1] as u8
                        } else {
                            digit
                        };
                        return Err(parser::ParseError::InvalidGroupLength {
                            expected: parser::Expected::Exact(
                                parser::GROUP_LENS[group],
                            ),
                            found: found as usize,
                            group,
                        });
                    }
                    _ => {
                        return Err(parser::ParseError::InvalidCharacter {
                            expected: "0123456789abcdefABCDEF-",
                            found: input[i_char..].chars().next().unwrap(),
                            index: i_char,
                        });
                    }
                }
                buffer[(digit / 2) as usize] = acc;
            }
            digit += 1;
        }
        
        
        
        
        if parser::ACC_GROUP_LENS[4] as u8 != digit {
            return Err(parser::ParseError::InvalidGroupLength {
                expected: parser::Expected::Exact(parser::GROUP_LENS[4]),
                found: (digit as usize - parser::ACC_GROUP_LENS[3]),
                group,
            });
        }
        Ok(Uuid::from_bytes(buffer))
    }
    
    pub fn is_nil(&self) -> bool {
        self.as_bytes().iter().all(|&b| b == 0)
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub fn encode_buffer() -> [u8; adapter::Urn::LENGTH] {
        [0; adapter::Urn::LENGTH]
    }
}
#[cfg(test)]
mod tests {
    extern crate std;
    use self::std::prelude::v1::*;
    use super::test_util;
    use prelude::*;
    #[test]
    fn test_nil() {
        let nil = Uuid::nil();
        let not_nil = test_util::new();
        let from_bytes = Uuid::from_bytes([
            4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87,
        ]);
        assert_eq!(from_bytes.get_version(), None);
        assert!(nil.is_nil());
        assert!(!not_nil.is_nil());
        assert_eq!(nil.get_version(), Some(Version::Nil));
        assert_eq!(not_nil.get_version(), Some(Version::Random))
    }
    #[test]
    fn test_predefined_namespaces() {
        assert_eq!(
            Uuid::NAMESPACE_DNS.to_hyphenated().to_string(),
            "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
        );
        assert_eq!(
            Uuid::NAMESPACE_URL.to_hyphenated().to_string(),
            "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
        );
        assert_eq!(
            Uuid::NAMESPACE_OID.to_hyphenated().to_string(),
            "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
        );
        assert_eq!(
            Uuid::NAMESPACE_X500.to_hyphenated().to_string(),
            "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
        );
    }
    #[cfg(feature = "v3")]
    #[test]
    fn test_get_version_v3() {
        let uuid =
            Uuid::new_v3(&Uuid::NAMESPACE_DNS, "rust-lang.org".as_bytes());
        assert_eq!(uuid.get_version().unwrap(), Version::Md5);
        assert_eq!(uuid.get_version_num(), 3);
    }
    #[test]
    fn test_get_variant() {
        let uuid1 = test_util::new();
        let uuid2 =
            Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
        let uuid3 =
            Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
        let uuid4 =
            Uuid::parse_str("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
        let uuid5 =
            Uuid::parse_str("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
        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);
    }
    #[test]
    fn test_parse_uuid_v4() {
        use adapter;
        use parser;
        const EXPECTED_UUID_LENGTHS: parser::Expected =
            parser::Expected::Any(&[
                adapter::Hyphenated::LENGTH,
                adapter::Simple::LENGTH,
            ]);
        const EXPECTED_GROUP_COUNTS: parser::Expected =
            parser::Expected::Any(&[1, 5]);
        const EXPECTED_CHARS: &'static str = "0123456789abcdefABCDEF-";
        
        assert_eq!(
            Uuid::parse_str(""),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 0,
            })
        );
        assert_eq!(
            Uuid::parse_str("!"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 1
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 37,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 35
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"),
            Err(parser::ParseError::InvalidCharacter {
                expected: EXPECTED_CHARS,
                found: 'G',
                index: 20,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4"),
            Err(parser::ParseError::InvalidGroupCount {
                expected: EXPECTED_GROUP_COUNTS,
                found: 2
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4"),
            Err(parser::ParseError::InvalidGroupCount {
                expected: EXPECTED_GROUP_COUNTS,
                found: 3,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"),
            Err(parser::ParseError::InvalidGroupCount {
                expected: EXPECTED_GROUP_COUNTS,
                found: 4,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 18,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"),
            Err(parser::ParseError::InvalidCharacter {
                expected: EXPECTED_CHARS,
                found: 'X',
                index: 18,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"),
            Err(parser::ParseError::InvalidGroupLength {
                expected: parser::Expected::Exact(4),
                found: 3,
                group: 1,
            })
        );
        
        
        assert_eq!(
            Uuid::parse_str("01020304-1112-2122-3132-41424344"),
            Err(parser::ParseError::InvalidGroupLength {
                expected: parser::Expected::Exact(12),
                found: 8,
                group: 4,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 31,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 33,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 33,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"),
            Err(parser::ParseError::InvalidCharacter {
                expected: EXPECTED_CHARS,
                found: '%',
                index: 15,
            })
        );
        assert_eq!(
            Uuid::parse_str("231231212212423424324323477343246663"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 36,
            })
        );
        
        assert!(Uuid::parse_str("00000000000000000000000000000000").is_ok());
        assert!(Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
        assert!(Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
        assert!(Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8").is_ok());
        assert!(Uuid::parse_str("01020304-1112-2122-3132-414243444546").is_ok());
        assert!(Uuid::parse_str(
            "urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8"
        )
        .is_ok());
        
        let nil = Uuid::nil();
        assert_eq!(
            Uuid::parse_str("00000000000000000000000000000000").unwrap(),
            nil
        );
        assert_eq!(
            Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
            nil
        );
        
        let uuid_orig = test_util::new();
        let orig_str = uuid_orig.to_string();
        let uuid_out = Uuid::parse_str(&orig_str).unwrap();
        assert_eq!(uuid_orig, uuid_out);
        
        assert_eq!(
            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
            Err(parser::ParseError::InvalidLength {
                expected: EXPECTED_UUID_LENGTHS,
                found: 31,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"),
            Err(parser::ParseError::InvalidCharacter {
                expected: EXPECTED_CHARS,
                found: 'X',
                index: 6,
            })
        );
        assert_eq!(
            Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"),
            Err(parser::ParseError::InvalidGroupLength {
                expected: parser::Expected::Exact(8),
                found: 6,
                group: 0,
            })
        );
        assert_eq!(
            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"),
            Err(parser::ParseError::InvalidGroupLength {
                expected: parser::Expected::Exact(4),
                found: 5,
                group: 3,
            })
        );
    }
    #[test]
    fn test_to_simple_string() {
        let uuid1 = test_util::new();
        let s = uuid1.to_simple().to_string();
        assert_eq!(s.len(), 32);
        assert!(s.chars().all(|c| c.is_digit(16)));
    }
    #[test]
    fn test_to_hyphenated_string() {
        let uuid1 = test_util::new();
        let s = uuid1.to_hyphenated().to_string();
        assert!(s.len() == 36);
        assert!(s.chars().all(|c| c.is_digit(16) || c == '-'));
    }
    #[test]
    fn test_upper_lower_hex() {
        use tests::std::fmt::Write;
        let mut buf = String::new();
        let u = test_util::new();
        macro_rules! check {
            ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
                $buf.clear();
                write!($buf, $format, $target).unwrap();
                assert!(buf.len() == $len);
                assert!($buf.chars().all($cond), "{}", $buf);
            };
        }
        check!(buf, "{:X}", u, 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
        check!(buf, "{:X}", u.to_hyphenated(), 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
        check!(buf, "{:X}", u.to_simple(), 32, |c| c.is_uppercase()
            || c.is_digit(10));
        check!(buf, "{:x}", u.to_hyphenated(), 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
        check!(buf, "{:x}", u.to_simple(), 32, |c| c.is_lowercase()
            || c.is_digit(10));
    }
    #[test]
    fn test_to_urn_string() {
        let uuid1 = test_util::new();
        let ss = uuid1.to_urn().to_string();
        let s = &ss[9..];
        assert!(ss.starts_with("urn:uuid:"));
        assert_eq!(s.len(), 36);
        assert!(s.chars().all(|c| c.is_digit(16) || c == '-'));
    }
    #[test]
    fn test_to_simple_string_matching() {
        let uuid1 = test_util::new();
        let hs = uuid1.to_hyphenated().to_string();
        let ss = uuid1.to_simple().to_string();
        let hsn = hs.chars().filter(|&c| c != '-').collect::<String>();
        assert_eq!(hsn, ss);
    }
    #[test]
    fn test_string_roundtrip() {
        let uuid = test_util::new();
        let hs = uuid.to_hyphenated().to_string();
        let uuid_hs = Uuid::parse_str(&hs).unwrap();
        assert_eq!(uuid_hs, uuid);
        let ss = uuid.to_string();
        let uuid_ss = Uuid::parse_str(&ss).unwrap();
        assert_eq!(uuid_ss, uuid);
    }
    #[test]
    fn test_from_fields() {
        let d1: u32 = 0xa1a2a3a4;
        let d2: u16 = 0xb1b2;
        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 expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
        let result = u.to_simple().to_string();
        assert_eq!(result, expected);
    }
    #[test]
    fn test_from_fields_le() {
        let d1: u32 = 0xa4a3a2a1;
        let d2: u16 = 0xb2b1;
        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 expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
        let result = u.to_simple().to_string();
        assert_eq!(result, expected);
    }
    #[test]
    fn test_as_fields() {
        let u = test_util::new();
        let (d1, d2, d3, d4) = u.as_fields();
        assert_ne!(d1, 0);
        assert_ne!(d2, 0);
        assert_ne!(d3, 0);
        assert_eq!(d4.len(), 8);
        assert!(!d4.iter().all(|&b| b == 0));
    }
    #[test]
    fn test_fields_roundtrip() {
        let d1_in: u32 = 0xa1a2a3a4;
        let d2_in: u16 = 0xb1b2;
        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 (d1_out, d2_out, d3_out, d4_out) = u.as_fields();
        assert_eq!(d1_in, d1_out);
        assert_eq!(d2_in, d2_out);
        assert_eq!(d3_in, d3_out);
        assert_eq!(d4_in, d4_out);
    }
    #[test]
    fn test_fields_le_roundtrip() {
        let d1_in: u32 = 0xa4a3a2a1;
        let d2_in: u16 = 0xb2b1;
        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 (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
        assert_eq!(d1_in, d1_out);
        assert_eq!(d2_in, d2_out);
        assert_eq!(d3_in, d3_out);
        assert_eq!(d4_in, d4_out);
    }
    #[test]
    fn test_fields_le_are_actually_le() {
        let d1_in: u32 = 0xa1a2a3a4;
        let d2_in: u16 = 0xb1b2;
        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 (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
        assert_eq!(d1_in, d1_out.swap_bytes());
        assert_eq!(d2_in, d2_out.swap_bytes());
        assert_eq!(d3_in, d3_out.swap_bytes());
        assert_eq!(d4_in, d4_out);
    }
    #[test]
    fn test_from_slice() {
        let b = [
            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
            0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
        ];
        let u = Uuid::from_slice(&b).unwrap();
        let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
        assert_eq!(u.to_simple().to_string(), expected);
    }
    #[test]
    fn test_from_bytes() {
        let b = [
            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
            0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
        ];
        let u = Uuid::from_bytes(b);
        let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
        assert_eq!(u.to_simple().to_string(), expected);
    }
    #[test]
    fn test_as_bytes() {
        let u = test_util::new();
        let ub = u.as_bytes();
        assert_eq!(ub.len(), 16);
        assert!(!ub.iter().all(|&b| b == 0));
    }
    #[test]
    fn test_bytes_roundtrip() {
        let b_in: ::Bytes = [
            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
            0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
        ];
        let u = Uuid::from_slice(&b_in).unwrap();
        let b_out = u.as_bytes();
        assert_eq!(&b_in, b_out);
    }
    #[test]
    #[allow(deprecated)]
    fn test_from_random_bytes() {
        let b = [
            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
            0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
        ];
        let u = Uuid::from_random_bytes(b);
        let expected = "a1a2a3a4b1b241c291d2d3d4d5d6d7d8";
        assert_eq!(u.to_simple().to_string(), expected);
    }
    #[test]
    fn test_iterbytes_impl_for_uuid() {
        let mut set = std::collections::HashSet::new();
        let id1 = test_util::new();
        let id2 = test_util::new2();
        set.insert(id1.clone());
        assert!(set.contains(&id1));
        assert!(!set.contains(&id2));
    }
}