use crate::{
std::{borrow::Borrow, fmt, ptr, str},
Yyid,
};
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 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 URN_PREFIX: &[u8; 9] = b"urn:yyid:";
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Hyphenated(Yyid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Simple(Yyid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Urn(Yyid);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Braced(Yyid);
#[inline]
const fn format_simple(src: &[u8; 16], upper: bool) -> [u8; 32] {
let lut = if upper { &UPPER } else { &LOWER };
let mut dst = [0; 32];
let mut i = 0;
while i < 16 {
let x = src[i];
dst[i * 2] = lut[(x >> 4) as usize];
dst[i * 2 + 1] = lut[(x & 0x0f) as usize];
i += 1;
}
dst
}
#[inline]
const fn format_hyphenated(src: &[u8; 16], upper: bool) -> [u8; 36] {
let lut = if upper { &UPPER } else { &LOWER };
let groups = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)];
let mut dst = [0; 36];
let mut group_idx = 0;
let mut i = 0;
while group_idx < 5 {
let (start, end) = groups[group_idx];
let mut j = start;
while j < end {
let x = src[i];
i += 1;
dst[j] = lut[(x >> 4) as usize];
dst[j + 1] = lut[(x & 0x0f) as usize];
j += 2;
}
if group_idx < 4 {
dst[end] = b'-';
}
group_idx += 1;
}
dst
}
#[inline]
fn encode_simple<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
let buf = &mut buffer[..Simple::LENGTH];
let dst = buf.as_mut_ptr();
unsafe {
ptr::write(dst.cast(), format_simple(src, upper));
str::from_utf8_unchecked_mut(buf)
}
}
#[inline]
fn encode_hyphenated<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
let buf = &mut buffer[..Hyphenated::LENGTH];
let dst = buf.as_mut_ptr();
unsafe {
ptr::write(dst.cast(), format_hyphenated(src, upper));
str::from_utf8_unchecked_mut(buf)
}
}
#[inline]
fn encode_braced<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
let buf = &mut buffer[..Braced::LENGTH];
buf[0] = b'{';
buf[Braced::LENGTH - 1] = b'}';
unsafe {
let dst = buf.as_mut_ptr().add(1);
ptr::write(dst.cast(), format_hyphenated(src, upper));
str::from_utf8_unchecked_mut(buf)
}
}
#[inline]
fn encode_urn<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
let buf = &mut buffer[..Urn::LENGTH];
buf[..9].copy_from_slice(URN_PREFIX);
unsafe {
let dst = buf.as_mut_ptr().add(9);
ptr::write(dst.cast(), format_hyphenated(src, upper));
str::from_utf8_unchecked_mut(buf)
}
}
impl Yyid {
#[inline]
pub const fn hyphenated(self) -> Hyphenated {
Hyphenated(self)
}
#[inline]
pub const fn as_hyphenated(&self) -> &Hyphenated {
unsafe { &*(self as *const Yyid as *const Hyphenated) }
}
#[inline]
pub const fn simple(self) -> Simple {
Simple(self)
}
#[inline]
pub const fn as_simple(&self) -> &Simple {
unsafe { &*(self as *const Yyid as *const Simple) }
}
#[inline]
pub const fn urn(self) -> Urn {
Urn(self)
}
#[inline]
pub const fn as_urn(&self) -> &Urn {
unsafe { &*(self as *const Yyid as *const Urn) }
}
#[inline]
pub const fn braced(self) -> Braced {
Braced(self)
}
#[inline]
pub const fn as_braced(&self) -> &Braced {
unsafe { &*(self as *const Yyid as *const Braced) }
}
}
impl Hyphenated {
pub const LENGTH: usize = 36;
pub const fn from_yyid(yyid: Yyid) -> Self {
Self(yyid)
}
pub const fn as_yyid(&self) -> &Yyid {
&self.0
}
pub const fn into_yyid(self) -> Yyid {
self.0
}
#[inline]
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_hyphenated(self.0.as_bytes(), buffer, false)
}
#[inline]
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_hyphenated(self.0.as_bytes(), buffer, true)
}
}
impl Simple {
const LENGTH: usize = 32;
pub const fn from_yyid(yyid: Yyid) -> Self {
Self(yyid)
}
pub const fn as_yyid(&self) -> &Yyid {
&self.0
}
pub const fn into_yyid(self) -> Yyid {
self.0
}
#[inline]
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_simple(self.0.as_bytes(), buffer, false)
}
#[inline]
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_simple(self.0.as_bytes(), buffer, true)
}
}
impl Urn {
const LENGTH: usize = 45;
pub const fn from_yyid(yyid: Yyid) -> Self {
Self(yyid)
}
pub const fn as_yyid(&self) -> &Yyid {
&self.0
}
pub const fn into_yyid(self) -> Yyid {
self.0
}
#[inline]
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_urn(self.0.as_bytes(), buffer, false)
}
#[inline]
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_urn(self.0.as_bytes(), buffer, true)
}
}
impl Braced {
const LENGTH: usize = 38;
pub const fn from_yyid(yyid: Yyid) -> Self {
Self(yyid)
}
pub const fn as_yyid(&self) -> &Yyid {
&self.0
}
pub const fn into_yyid(self) -> Yyid {
self.0
}
#[inline]
pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_braced(self.0.as_bytes(), buffer, false)
}
#[inline]
pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
encode_braced(self.0.as_bytes(), buffer, true)
}
}
macro_rules! impl_fmt_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; Self::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; Self::LENGTH]))
}
}
impl_fmt_from!($T<$($a),*>);
)+}
}
macro_rules! impl_fmt_from {
($T:ident<>) => {
impl From<Yyid> for $T {
#[inline]
fn from(f: Yyid) -> Self {
$T(f)
}
}
impl From<$T> for Yyid {
#[inline]
fn from(f: $T) -> Self {
f.into_yyid()
}
}
impl AsRef<Yyid> for $T {
#[inline]
fn as_ref(&self) -> &Yyid {
&self.0
}
}
impl Borrow<Yyid> for $T {
#[inline]
fn borrow(&self) -> &Yyid {
&self.0
}
}
};
($T:ident<$a:lifetime>) => {
impl<$a> From<&$a Yyid> for $T<$a> {
#[inline]
fn from(f: &$a Yyid) -> Self {
$T::from_yyid_ref(f)
}
}
impl<$a> From<$T<$a>> for &$a Yyid {
#[inline]
fn from(f: $T<$a>) -> &$a Yyid {
f.0
}
}
impl<$a> AsRef<Yyid> for $T<$a> {
#[inline]
fn as_ref(&self) -> &Yyid {
self.0
}
}
impl<$a> Borrow<Yyid> for $T<$a> {
#[inline]
fn borrow(&self) -> &Yyid {
self.0
}
}
};
}
impl_fmt_traits! {
Hyphenated<>,
Simple<>,
Urn<>,
Braced<>
}