lunar-lib 0.11.1

Common utilities for lunar applications
Documentation
use std::fmt;

use rand::{
    RngExt,
    distr::{Distribution, StandardUniform},
};

#[derive(Debug)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(transparent)
)]
pub struct Id<T: ?Sized>(
    #[serde(with = "hex::serde")] [u8; 32],
    std::marker::PhantomData<T>,
);
pub const ID_SIZE: usize = 32;

impl<T> Id<T> {
    #[must_use]
    pub fn cast<U>(self) -> Id<U> {
        Id::<U>(self.0, std::marker::PhantomData)
    }

    #[must_use]
    pub fn generate() -> Id<T> {
        rand::rng().random()
    }
}

impl<T> Distribution<Id<T>> for StandardUniform {
    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Id<T> {
        Id(rng.random(), std::marker::PhantomData)
    }
}

impl<T> Clone for Id<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for Id<T> {}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl<T> Eq for Id<T> {}

impl<T> std::hash::Hash for Id<T> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl<T> fmt::Display for Id<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        hex::encode(self.0).fmt(f)
    }
}

impl<T> std::str::FromStr for Id<T> {
    type Err = hex::FromHexError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut id = [0u8; 32];
        hex::decode_to_slice(s, &mut id)?;
        Ok(Self(id, std::marker::PhantomData))
    }
}

impl<T> hex::FromHex for Id<T> {
    type Error = hex::FromHexError;

    fn from_hex<T1: AsRef<[u8]>>(hex: T1) -> Result<Self, Self::Error> {
        let id = <[u8; 32]>::from_hex(hex)?;
        Ok(Self(id, std::marker::PhantomData))
    }
}

impl<T> AsRef<[u8]> for Id<T> {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl<T> std::ops::Deref for Id<T> {
    type Target = [u8; 32];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> From<[u8; 32]> for Id<T> {
    fn from(value: [u8; 32]) -> Self {
        Self(value, std::marker::PhantomData)
    }
}

impl<T> From<Id<T>> for [u8; 32] {
    fn from(value: Id<T>) -> Self {
        value.0
    }
}

impl<T> TryFrom<Vec<u8>> for Id<T> {
    type Error = std::array::TryFromSliceError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Self::try_from(&*value)
    }
}

impl<T> TryFrom<&[u8]> for Id<T> {
    type Error = std::array::TryFromSliceError;

    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
        let value: [u8; 32] = value.try_into()?;
        Ok(Self(value, std::marker::PhantomData))
    }
}