148 lines
3.0 KiB
Rust
148 lines
3.0 KiB
Rust
use crate::error::{Error, ErrorKind};
|
|
|
|
// UUID (RFC 4122) v4 implementation
|
|
// Heavily based on the 'uuid' crate: https://docs.rs/uuid/latest/uuid/
|
|
|
|
mod error;
|
|
mod parse;
|
|
mod rng;
|
|
|
|
pub mod fmt;
|
|
pub mod serde;
|
|
pub mod v4;
|
|
|
|
pub type Bytes = [u8; 16];
|
|
|
|
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
#[repr(transparent)]
|
|
pub struct Uuid(Bytes);
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
#[repr(u8)]
|
|
pub enum Variant {
|
|
NCS = 0u8,
|
|
Default = 0x80,
|
|
Microsoft = 0xc0,
|
|
Future = 0xe0,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
#[non_exhaustive]
|
|
#[repr(u8)]
|
|
pub enum Version {
|
|
Nil = 0,
|
|
Time = 1,
|
|
DCE = 2,
|
|
MD5 = 3,
|
|
Random = 4,
|
|
SHA1 = 5,
|
|
Unknown = u8::MAX,
|
|
}
|
|
|
|
impl Uuid {
|
|
pub fn new_nil() -> Self {
|
|
Uuid(Uuid::nil_bytes())
|
|
}
|
|
|
|
pub fn from_bytes(bytes: Bytes) -> Self {
|
|
Uuid(bytes)
|
|
}
|
|
|
|
pub fn from_slice(b: &[u8]) -> Result<Uuid, Error> {
|
|
if b.len() != 16 {
|
|
return Err(Error(ErrorKind::ByteLength { len: b.len() }));
|
|
}
|
|
|
|
let mut bytes: Bytes = Uuid::nil_bytes();
|
|
bytes.copy_from_slice(b);
|
|
Ok(Uuid::from_bytes(bytes))
|
|
}
|
|
|
|
pub const fn get_variant(&self) -> Variant {
|
|
match self.as_bytes()[8] {
|
|
x if x & 0x80 == 0 => Variant::NCS,
|
|
x if x & 0x40 == 0 => Variant::Default,
|
|
x if x & 0x20 == 0 => Variant::Microsoft,
|
|
_ => Variant::Future
|
|
}
|
|
}
|
|
|
|
pub const fn get_version_num(&self) -> u8 {
|
|
self.as_bytes()[6] >> 4
|
|
}
|
|
|
|
pub const fn get_version(&self) -> Version {
|
|
match self.get_version_num() {
|
|
0 => Version::Nil,
|
|
1 => Version::Time,
|
|
2 => Version::DCE,
|
|
3 => Version::MD5,
|
|
4 => Version::Random,
|
|
5 => Version::SHA1,
|
|
_ => Version::Unknown
|
|
}
|
|
}
|
|
|
|
pub const fn as_u128(&self) -> u128 {
|
|
u128::from_be_bytes(*self.as_bytes())
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_bytes(&self) -> &Bytes {
|
|
&self.0
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn into_bytes(self) -> Bytes {
|
|
self.0
|
|
}
|
|
|
|
pub const fn is_nil(&self) -> bool {
|
|
self.as_u128() == u128::MIN
|
|
}
|
|
|
|
pub const fn encode_buffer() -> [u8; fmt::UUID_STR_LEN] {
|
|
[0; fmt::UUID_STR_LEN]
|
|
}
|
|
|
|
#[inline]
|
|
const fn nil_bytes() -> Bytes {
|
|
[0u8; 16]
|
|
}
|
|
|
|
#[inline]
|
|
fn set_variant(bytes: &mut Bytes, variant: Variant) {
|
|
let variant = variant as u8;
|
|
let byte = bytes[8] & 0xf;
|
|
|
|
bytes[8] = variant | byte;
|
|
}
|
|
|
|
#[inline]
|
|
fn set_version(bytes: &mut Bytes, version: Version) {
|
|
let version = (version as u8) << 4;
|
|
let byte = bytes[6] & 0xf;
|
|
|
|
bytes[6] = version | byte;
|
|
}
|
|
}
|
|
|
|
impl Default for Uuid {
|
|
fn default() -> Self {
|
|
Uuid::new_nil()
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for Uuid {
|
|
#[inline]
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl ToString for Uuid {
|
|
fn to_string(&self) -> String {
|
|
format!("{:02x}", self)
|
|
}
|
|
}
|