use crate::prelude::*;
use crate::std::{fmt, str};
#[cfg(feature = "serde")]
pub mod compact;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Hyphenated(Uuid);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HyphenatedRef<'a>(&'a Uuid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Simple(Uuid);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SimpleRef<'a>(&'a Uuid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Urn(Uuid);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UrnRef<'a>(&'a Uuid);
impl Uuid {
#[inline]
pub const fn to_hyphenated(self) -> Hyphenated {
Hyphenated::from_uuid(self)
}
#[inline]
pub const fn to_hyphenated_ref(&self) -> HyphenatedRef<'_> {
HyphenatedRef::from_uuid_ref(self)
}
#[inline]
pub const fn to_simple(self) -> Simple {
Simple::from_uuid(self)
}
#[inline]
pub const fn to_simple_ref(&self) -> SimpleRef<'_> {
SimpleRef::from_uuid_ref(self)
}
#[inline]
pub const fn to_urn(self) -> Urn {
Urn::from_uuid(self)
}
#[inline]
pub const fn to_urn_ref(&self) -> UrnRef<'_> {
UrnRef::from_uuid_ref(self)
}
}
const UPPER: [u8; 16] = [
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B',
b'C', b'D', b'E', b'F',
];
const LOWER: [u8; 16] = [
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b',
b'c', b'd', b'e', b'f',
];
const BYTE_POSITIONS: [usize; 6] = [0, 4, 6, 8, 10, 16];
const HYPHEN_POSITIONS: [usize; 4] = [8, 13, 18, 23];
fn encode<'a>(
full_buffer: &'a mut [u8],
start: usize,
uuid: &Uuid,
hyphens: bool,
upper: bool,
) -> &'a mut str {
let len = if hyphens { 36 } else { 32 };
{
let buffer = &mut full_buffer[start..start + len];
let bytes = uuid.as_bytes();
let hex = if upper { &UPPER } else { &LOWER };
for group in 0..5 {
let hyphens_before = if hyphens { group } else { 0 };
for idx in BYTE_POSITIONS[group]..BYTE_POSITIONS[group + 1] {
let b = bytes[idx];
let out_idx = hyphens_before + 2 * idx;
buffer[out_idx] = hex[(b >> 4) as usize];
buffer[out_idx + 1] = hex[(b & 0b1111) as usize];
}
if group != 4 && hyphens {
buffer[HYPHEN_POSITIONS[group]] = b'-';
}
}
}
str::from_utf8_mut(&mut full_buffer[..start + len])
.expect("found non-ASCII output characters while encoding a UUID")
}
impl Hyphenated {
pub const LENGTH: usize = 36;
pub const fn from_uuid(uuid: Uuid) -> Self {
Hyphenated(uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, &self.0, true, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, &self.0, true, true)
}
}
impl<'a> HyphenatedRef<'a> {
pub const LENGTH: usize = 36;
pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
HyphenatedRef(uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, self.0, true, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, self.0, true, true)
}
}
impl Simple {
pub const LENGTH: usize = 32;
pub const fn from_uuid(uuid: Uuid) -> Self {
Simple(uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, &self.0, false, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, &self.0, false, true)
}
}
impl<'a> SimpleRef<'a> {
pub const LENGTH: usize = 32;
pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
SimpleRef(uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, self.0, false, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode(buffer, 0, self.0, false, true)
}
}
impl Urn {
pub const LENGTH: usize = 45;
pub const fn from_uuid(uuid: Uuid) -> Self {
Urn(uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
buffer[..9].copy_from_slice(b"urn:uuid:");
encode(buffer, 9, &self.0, true, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
buffer[..9].copy_from_slice(b"urn:uuid:");
encode(buffer, 9, &self.0, true, true)
}
}
impl<'a> UrnRef<'a> {
pub const LENGTH: usize = 45;
pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
UrnRef(&uuid)
}
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
buffer[..9].copy_from_slice(b"urn:uuid:");
encode(buffer, 9, self.0, true, false)
}
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
buffer[..9].copy_from_slice(b"urn:uuid:");
encode(buffer, 9, self.0, true, true)
}
}
macro_rules! impl_adapter_traits {
($($T:ident<$($a:lifetime),*>),+) => {$(
impl<$($a),*> fmt::Display for $T<$($a),*> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
impl<$($a),*> fmt::LowerHex for $T<$($a),*> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.encode_lower(&mut [0; $T::LENGTH]))
}
}
impl<$($a),*> fmt::UpperHex for $T<$($a),*> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.encode_upper(&mut [0; $T::LENGTH]))
}
}
impl_adapter_from!($T<$($a),*>);
)+}
}
macro_rules! impl_adapter_from {
($T:ident<>) => {
impl From<Uuid> for $T {
#[inline]
fn from(f: Uuid) -> Self {
$T::from_uuid(f)
}
}
};
($T:ident<$a:lifetime>) => {
impl<$a> From<&$a Uuid> for $T<$a> {
#[inline]
fn from(f: &$a Uuid) -> Self {
$T::from_uuid_ref(f)
}
}
};
}
impl_adapter_traits! {
Hyphenated<>,
HyphenatedRef<'a>,
Simple<>,
SimpleRef<'a>,
Urn<>,
UrnRef<'a>
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn hyphenated_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_hyphenated().encode_lower(&mut buf).len();
assert_eq!(len, super::Hyphenated::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
fn hyphenated_ref_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_hyphenated().encode_lower(&mut buf).len();
assert_eq!(len, super::HyphenatedRef::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
fn simple_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_simple().encode_lower(&mut buf).len();
assert_eq!(len, super::Simple::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
fn simple_ref_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_simple().encode_lower(&mut buf).len();
assert_eq!(len, super::SimpleRef::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
fn urn_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_urn().encode_lower(&mut buf).len();
assert_eq!(len, super::Urn::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
fn urn_ref_trailing() {
let mut buf = [b'x'; 100];
let len = Uuid::nil().to_urn().encode_lower(&mut buf).len();
assert_eq!(len, super::UrnRef::LENGTH);
assert!(buf[len..].iter().all(|x| *x == b'x'));
}
#[test]
#[should_panic]
fn hyphenated_too_small() {
Uuid::nil().to_hyphenated().encode_lower(&mut [0; 35]);
}
#[test]
#[should_panic]
fn hyphenated_ref_too_small() {
Uuid::nil().to_hyphenated_ref().encode_lower(&mut [0; 35]);
}
#[test]
#[should_panic]
fn simple_too_small() {
Uuid::nil().to_simple().encode_lower(&mut [0; 31]);
}
#[test]
#[should_panic]
fn simple_ref_too_small() {
Uuid::nil().to_simple_ref().encode_lower(&mut [0; 31]);
}
#[test]
#[should_panic]
fn urn_too_small() {
Uuid::nil().to_urn().encode_lower(&mut [0; 44]);
}
#[test]
#[should_panic]
fn urn_ref_too_small() {
Uuid::nil().to_urn_ref().encode_lower(&mut [0; 44]);
}
}