#![no_std]
extern crate alloc;
use alloc::format;
use alloc::string::String;
use core::fmt::{Display, Formatter};
#[derive(Copy, Clone, Default, Eq, PartialEq, Debug, PartialOrd, Ord, Hash)]
pub struct Euui([u128; 4]);
impl Euui {
pub fn zero() -> Self {
Self([0, 0, 0, 0])
}
pub fn from_be_guids(guids: [u128; 4]) -> Self {
Self(guids)
}
pub fn from_be_bytes(bytes: [u8; 64]) -> Self {
let mut guids = [0u128; 4];
for i in 0..4 {
guids[i] =
u128::from_be_bytes(bytes[i * 16..(i + 1) * 16].try_into().expect("Logic error"));
}
Self(guids)
}
pub fn from_be_longs(bytes: [u64; 8]) -> Self {
let mut guids = [0u128; 4];
for i in 0..4 {
let long_a = bytes[i * 2].to_be_bytes();
let long_b = bytes[i * 2 + 1].to_be_bytes();
let mut buf = [0u8; 16];
buf[..8].copy_from_slice(&long_a);
buf[8..].copy_from_slice(&long_b);
guids[i] = u128::from_be_bytes(buf);
}
Self(guids)
}
pub fn u128(&self, index: usize) -> Option<u128> {
if index >= self.0.len() {
None
} else {
Some(self.0[index])
}
}
pub fn u64(&self, index: usize) -> Option<u64> {
if index >= self.0.len() * 2 {
None
} else {
let start = index * 8;
let end = start + 8;
Some(u64::from_be_bytes(
self.to_be_bytes()[start..end]
.try_into()
.expect("Logic error"),
))
}
}
pub fn u8(&self, index: usize) -> Option<u8> {
if index >= self.0.len() * 16 {
None
} else {
let wide_index = index / 16;
let byte_index = index % 16;
Some(self.u128(wide_index).unwrap().to_be_bytes()[byte_index])
}
}
pub fn to_be_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
for (i, guid) in self.0.iter().enumerate() {
let part = guid.to_be_bytes();
bytes[i * 16..(i + 1) * 16].copy_from_slice(&part);
}
bytes
}
pub fn to_be_longs(&self) -> [u64; 8] {
let mut longs = [0u64; 8];
for (i, guid) in self.0.iter().enumerate() {
let bytes = guid.to_be_bytes();
longs[i * 2] = u64::from_be_bytes(bytes[0..8].try_into().expect("Logic error"));
longs[i * 2 + 1] = u64::from_be_bytes(bytes[8..16].try_into().expect("Logic error"));
}
longs
}
pub fn to_be_guids(&self) -> [u128; 4] {
self.0
}
pub fn format(&self) -> String {
format!(
"{:032x}-{:032x}\n{:032x}-{:032x}",
self.0[0], self.0[1], self.0[2], self.0[3]
)
}
}
impl Display for Euui {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{:032x}{:032x}{:032x}{:032x}",
self.0[0], self.0[1], self.0[2], self.0[3]
)
}
}
#[cfg(feature = "random")]
mod random;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(test)]
mod tests {
use crate::Euui;
use alloc::string::ToString;
use alloc::format;
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[test]
fn test_zero() {
let euui = Euui::default();
assert_eq!(
euui.to_string(),
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
);
}
#[test]
#[cfg(feature = "random")]
fn test_non_zero() {
let euui = Euui::random();
assert_ne!(
euui.to_string(),
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
);
}
#[test]
fn test_from_be_guids() {
let guids = [1u128, 2, 3, 4];
let euui = Euui::from_be_guids(guids);
assert_eq!(euui.to_be_guids(), guids);
}
#[test]
fn test_from_be_bytes() {
let mut bytes = [0u8; 64];
for i in 0..64 {
bytes[i] = i as u8;
}
let euui = Euui::from_be_bytes(bytes);
assert_eq!(euui.to_be_bytes(), bytes);
}
#[test]
fn test_from_be_longs() {
let longs = [1u64, 2, 3, 4, 5, 6, 7, 8];
let euui = Euui::from_be_longs(longs);
assert_eq!(euui.to_be_longs(), longs);
}
#[test]
fn test_accessors() {
let mut bytes = [0u8; 64];
for i in 0..64 {
bytes[i] = i as u8;
}
let euui = Euui::from_be_bytes(bytes);
for i in 0..4 {
assert_eq!(euui.u128(i).unwrap(), u128::from_be_bytes(bytes[i * 16..(i + 1) * 16].try_into().unwrap()));
}
assert!(euui.u128(4).is_none());
for i in 0..8 {
let start = i * 8;
let end = start + 8;
assert_eq!(euui.u64(i).unwrap(), u64::from_be_bytes(bytes[start..end].try_into().unwrap()));
}
assert!(euui.u64(8).is_none());
for i in 0..64 {
assert_eq!(euui.u8(i).unwrap(), bytes[i]);
}
assert!(euui.u8(64).is_none());
}
#[test]
fn test_format_and_display() {
let guids = [1u128, 2, 3, 4];
let euui = Euui::from_be_guids(guids);
let formatted = euui.format();
assert_eq!(
formatted,
format!(
"{:032x}-{:032x}\n{:032x}-{:032x}",
guids[0], guids[1], guids[2], guids[3]
)
);
let display = euui.to_string();
assert_eq!(
display,
format!("{:032x}{:032x}{:032x}{:032x}", guids[0], guids[1], guids[2], guids[3])
);
}
#[test]
#[cfg(feature = "random")]
fn test_random_from_parts() {
let first = 0x1u128;
let second = 0x2u128;
let third = 0x3u128;
let fourth = 0x4u128;
let e1 = Euui::random_from_first(first);
assert_eq!(e1.u128(0).unwrap(), first);
let e2 = Euui::random_from_second(second);
assert_eq!(e2.u128(1).unwrap(), second);
let e3 = Euui::random_from_third(third);
assert_eq!(e3.u128(2).unwrap(), third);
let e4 = Euui::random_from_fourth(fourth);
assert_eq!(e4.u128(3).unwrap(), fourth);
}
#[test]
#[cfg(feature = "random")]
fn test_regenerate_parts() {
let euui = Euui::random();
let r1 = euui.regenerate_first();
assert_ne!(r1.u128(0), euui.u128(0));
assert_eq!(r1.u128(1), euui.u128(1));
assert_eq!(r1.u128(2), euui.u128(2));
assert_eq!(r1.u128(3), euui.u128(3));
let r2 = euui.regenerate_second();
assert_ne!(r2.u128(1), euui.u128(1));
assert_eq!(r2.u128(0), euui.u128(0));
assert_eq!(r2.u128(2), euui.u128(2));
assert_eq!(r2.u128(3), euui.u128(3));
let r3 = euui.regenerate_third();
assert_ne!(r3.u128(2), euui.u128(2));
assert_eq!(r3.u128(0), euui.u128(0));
assert_eq!(r3.u128(1), euui.u128(1));
assert_eq!(r3.u128(3), euui.u128(3));
let r4 = euui.regenerate_fourth();
assert_ne!(r4.u128(3), euui.u128(3));
assert_eq!(r4.u128(0), euui.u128(0));
assert_eq!(r4.u128(1), euui.u128(1));
assert_eq!(r4.u128(2), euui.u128(2));
}
#[test]
#[cfg(feature = "uuid")]
fn test_uuid_functions() {
let base = Euui::zero();
let uuids = [
Uuid::from_u128(1),
Uuid::from_u128(2),
Uuid::from_u128(3),
Uuid::from_u128(4),
];
let with_part = base.with_uuid_part(uuids[2], 2);
assert_eq!(with_part.u128(2).unwrap(), uuids[2].as_u128());
let f = base.with_first(uuids[0]);
assert_eq!(f.u128(0).unwrap(), uuids[0].as_u128());
let s = base.with_second(uuids[1]);
assert_eq!(s.u128(1).unwrap(), uuids[1].as_u128());
let t = base.with_third(uuids[2]);
assert_eq!(t.u128(2).unwrap(), uuids[2].as_u128());
let fo = base.with_fourth(uuids[3]);
assert_eq!(fo.u128(3).unwrap(), uuids[3].as_u128());
let from = Euui::from_uuids(uuids);
assert_eq!(from.to_be_guids(), [1u128, 2, 3, 4]);
#[cfg(feature = "random_uuid")]
{
let r = Euui::random_uuids();
let bytes = r.to_be_bytes();
assert_ne!(bytes, [0u8; 64]);
}
for i in 0..4 {
assert_eq!(from.uuid(i).unwrap().as_u128(), uuids[i].as_u128());
}
assert!(from.uuid(4).is_none());
}
}