use crate::{ParseTnidError, Tnid, TnidName};
impl<Name: TnidName> From<Tnid<Name>> for uuid::Uuid {
fn from(tnid: Tnid<Name>) -> Self {
uuid::Uuid::from_u128(tnid.as_u128())
}
}
impl<Name: TnidName> TryFrom<uuid::Uuid> for Tnid<Name> {
type Error = ParseTnidError;
fn try_from(uuid: uuid::Uuid) -> Result<Self, Self::Error> {
Tnid::<Name>::from_u128(uuid.as_u128())
}
}
#[cfg(all(test, feature = "time", feature = "rand"))]
mod tests {
use super::*;
use crate::{Case, NameStr};
struct TestId;
impl TnidName for TestId {
const ID_NAME: NameStr<'static> = NameStr::new_const("test");
}
struct UserId;
impl TnidName for UserId {
const ID_NAME: NameStr<'static> = NameStr::new_const("user");
}
struct A;
impl TnidName for A {
const ID_NAME: NameStr<'static> = NameStr::new_const("a");
}
struct Zzzz;
impl TnidName for Zzzz {
const ID_NAME: NameStr<'static> = NameStr::new_const("zzzz");
}
#[test]
fn test_roundtrip_via_uuid_type_v0() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
let tnid_back: Tnid<TestId> = uuid.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_uuid_type_v1() {
let tnid = Tnid::<TestId>::new_v1();
let uuid: uuid::Uuid = tnid.into();
let tnid_back: Tnid<TestId> = uuid.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_u128_v0() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
let u128_val = uuid.as_u128();
let uuid2 = uuid::Uuid::from_u128(u128_val);
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_u128_v1() {
let tnid = Tnid::<TestId>::new_v1();
let uuid: uuid::Uuid = tnid.into();
let u128_val = uuid.as_u128();
let uuid2 = uuid::Uuid::from_u128(u128_val);
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_uuid_string_v0() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
let uuid_str = uuid.to_string();
let uuid2: uuid::Uuid = uuid_str.parse().expect("should parse UUID string");
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_uuid_string_v1() {
let tnid = Tnid::<TestId>::new_v1();
let uuid: uuid::Uuid = tnid.into();
let uuid_str = uuid.to_string();
let uuid2: uuid::Uuid = uuid_str.parse().expect("should parse UUID string");
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_bytes_v0() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
let bytes = uuid.as_bytes();
let uuid2 = uuid::Uuid::from_bytes(*bytes);
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_roundtrip_via_bytes_v1() {
let tnid = Tnid::<TestId>::new_v1();
let uuid: uuid::Uuid = tnid.into();
let bytes = uuid.as_bytes();
let uuid2 = uuid::Uuid::from_bytes(*bytes);
let tnid_back: Tnid<TestId> = uuid2.try_into().expect("should convert back");
assert_eq!(tnid.as_u128(), tnid_back.as_u128());
}
#[test]
fn test_tnid_converts_to_uuid_v8() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
assert_eq!(uuid.get_version_num(), 8);
}
#[test]
fn test_tnid_converts_to_rfc4122_variant() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
assert_eq!(uuid.get_variant(), uuid::Variant::RFC4122);
}
#[test]
fn test_uuid_string_representation() {
let tnid = Tnid::<TestId>::new_v0();
let uuid: uuid::Uuid = tnid.into();
let uuid_str = uuid.to_string();
let tnid_uuid_str = tnid.to_uuid_string(Case::Lower);
assert_eq!(uuid_str, tnid_uuid_str);
}
#[test]
fn test_wrong_uuid_version_rejected() {
let uuid_v4 = uuid::Uuid::new_v4();
assert_eq!(uuid_v4.get_version_num(), 4);
let result = Tnid::<TestId>::try_from(uuid_v4);
assert!(result.is_err());
assert_eq!(
result.expect_err("wrong UUID version should be rejected"),
ParseTnidError::InvalidUuidBits
);
}
#[test]
fn test_invalid_name_encoding_rejected() {
let tnid_user = Tnid::<UserId>::new_v0();
let uuid: uuid::Uuid = tnid_user.into();
let result = Tnid::<TestId>::try_from(uuid);
assert!(result.is_err());
assert!(matches!(
result.expect_err("mismatched TNID name should be rejected"),
ParseTnidError::NameMismatch { .. }
));
}
#[test]
fn test_different_name_lengths() {
let tnid_a = Tnid::<A>::new_v0();
let uuid_a: uuid::Uuid = tnid_a.into();
let tnid_a_back: Tnid<A> = uuid_a.try_into().expect("1-char name should work");
assert_eq!(tnid_a.as_u128(), tnid_a_back.as_u128());
let tnid_zzzz = Tnid::<Zzzz>::new_v0();
let uuid_zzzz: uuid::Uuid = tnid_zzzz.into();
let tnid_zzzz_back: Tnid<Zzzz> = uuid_zzzz.try_into().expect("4-char name should work");
assert_eq!(tnid_zzzz.as_u128(), tnid_zzzz_back.as_u128());
let tnid_user = Tnid::<UserId>::new_v0();
let uuid_user: uuid::Uuid = tnid_user.into();
let tnid_user_back: Tnid<UserId> = uuid_user.try_into().expect("4-char name should work");
assert_eq!(tnid_user.as_u128(), tnid_user_back.as_u128());
}
#[test]
fn test_known_tnid_value() {
let test_u128 = Tnid::<TestId>::new_v0().as_u128();
let tnid = Tnid::<TestId>::from_u128(test_u128).expect("should create from u128");
let uuid: uuid::Uuid = tnid.into();
assert_eq!(uuid.as_u128(), test_u128);
let tnid_back: Tnid<TestId> = uuid.try_into().expect("should convert back");
assert_eq!(tnid_back.as_u128(), test_u128);
}
}