use core::convert::TryFrom;
use std::{fmt, num::NonZeroU128};
use crate::{
error::{Error, ErrorKind},
Uuid,
};
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct NonNilUuid(NonZeroU128);
impl fmt::Display for NonNilUuid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", Uuid::from(*self))
}
}
impl PartialEq<Uuid> for NonNilUuid {
fn eq(&self, other: &Uuid) -> bool {
self.get() == *other
}
}
impl PartialEq<NonNilUuid> for Uuid {
fn eq(&self, other: &NonNilUuid) -> bool {
*self == other.get()
}
}
impl NonNilUuid {
pub const fn new(uuid: Uuid) -> Option<Self> {
match NonZeroU128::new(uuid.as_u128()) {
Some(non_nil) => Some(NonNilUuid(non_nil)),
None => None,
}
}
pub const unsafe fn new_unchecked(uuid: Uuid) -> Self {
NonNilUuid(unsafe { NonZeroU128::new_unchecked(uuid.as_u128()) })
}
#[inline]
pub const fn get(self) -> Uuid {
Uuid::from_u128(self.0.get())
}
}
impl From<NonNilUuid> for Uuid {
fn from(non_nil: NonNilUuid) -> Self {
Uuid::from_u128(non_nil.0.get())
}
}
impl TryFrom<Uuid> for NonNilUuid {
type Error = Error;
fn try_from(uuid: Uuid) -> Result<Self, Self::Error> {
NonZeroU128::new(uuid.as_u128())
.map(Self)
.ok_or(Error(ErrorKind::Nil))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_non_nil_with_option_size() {
assert_eq!(
std::mem::size_of::<Option<NonNilUuid>>(),
std::mem::size_of::<Uuid>()
);
}
#[test]
fn test_non_nil() {
let uuid = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
assert_eq!(Uuid::from(NonNilUuid::try_from(uuid).unwrap()), uuid);
assert_eq!(NonNilUuid::new(uuid).unwrap(), uuid);
assert_eq!(unsafe { NonNilUuid::new_unchecked(uuid) }, uuid);
assert!(NonNilUuid::try_from(Uuid::nil()).is_err());
assert!(NonNilUuid::new(Uuid::nil()).is_none());
}
}