caretta-sync/tripod-id/src/double.rs

135 lines
3.6 KiB
Rust
Raw Normal View History

2025-09-13 08:39:06 +09:00
use std::{fmt::Display, str::FromStr};
use rand::{distributions::Standard, prelude::Distribution, Rng};
2025-09-23 22:20:18 +09:00
use crate::{utils::is_delimiter, Error, TripodId, Single};
2025-09-13 08:39:06 +09:00
#[derive(Copy, Clone, Debug, PartialEq)]
2025-09-23 22:20:18 +09:00
pub struct Double{
inner: (Single, Single)
2025-09-13 08:39:06 +09:00
}
2025-09-23 22:20:18 +09:00
impl TripodId for Double{
2025-09-13 08:39:06 +09:00
type SizeType = u32;
2025-09-23 22:20:18 +09:00
const SIZE: Self::SizeType = (Single::SIZE as u32).pow(2);
2025-09-13 08:39:06 +09:00
/// ```
2025-09-23 22:20:18 +09:00
/// use tripod_id::{TripodId, Double};
2025-09-13 08:39:06 +09:00
/// use std::str::FromStr;
///
2025-09-23 22:20:18 +09:00
/// assert_eq!(Double::NIL, Double::from_str("000-000").unwrap());
/// assert_eq!(Double::NIL, Double::try_from(0).unwrap());
2025-09-13 08:39:06 +09:00
/// ```
const NIL: Self = Self{
2025-09-23 22:20:18 +09:00
inner: (Single::NIL, Single::NIL)
2025-09-13 08:39:06 +09:00
};
/// ```
2025-09-23 22:20:18 +09:00
/// use tripod_id::{TripodId, Double};
2025-09-13 08:39:06 +09:00
/// use std::str::FromStr;
///
2025-09-23 22:20:18 +09:00
/// assert_eq!(Double::MAX, Double::from_str("zzz-zzz").unwrap());
/// assert_eq!(Double::MAX, Double::try_from(1291467968).unwrap());
2025-09-13 08:39:06 +09:00
/// ```
const MAX: Self = Self{
2025-09-23 22:20:18 +09:00
inner: (Single::MAX, Single::MAX)
2025-09-13 08:39:06 +09:00
};
2025-09-13 12:29:59 +09:00
#[cfg(test)]
fn is_valid(&self) -> bool {
self.inner.0.is_valid() && self.inner.1.is_valid() && (u32::from(*self) < Self::SIZE)
2025-09-13 12:29:59 +09:00
}
2025-09-13 08:39:06 +09:00
}
2025-09-23 22:20:18 +09:00
impl Display for Double {
2025-09-13 08:39:06 +09:00
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}-{}", self.inner.0, self.inner.1)
}
}
2025-09-23 22:20:18 +09:00
impl FromStr for Double {
2025-09-13 08:39:06 +09:00
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
inner : match s.len() {
7 => {
2025-09-13 12:29:59 +09:00
let delimiter = s[3..4].chars().next().unwrap();
if is_delimiter(delimiter) {
2025-09-23 22:20:18 +09:00
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[4..7])?))
2025-09-13 12:29:59 +09:00
} else {
Err(Error::InvalidDelimiter{
found: vec![delimiter],
raw: s.to_string()
})
2025-09-13 08:39:06 +09:00
}
}
6 => {
2025-09-23 22:20:18 +09:00
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[3..6])?))
2025-09-13 08:39:06 +09:00
}
2025-09-13 12:29:59 +09:00
x => Err(Error::InvalidLength{
expected: (6, 7),
found: x,
raw: s.to_string()
})
2025-09-13 08:39:06 +09:00
}?
})
}
}
2025-09-23 22:20:18 +09:00
impl Distribution<Double> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Double {
Double {
2025-09-13 08:39:06 +09:00
inner: (rng.r#gen(), rng.r#gen())
}
}
}
2025-09-23 22:20:18 +09:00
impl TryFrom<u32> for Double {
2025-09-13 08:39:06 +09:00
type Error = Error;
fn try_from(value: u32) -> Result<Self, Self::Error> {
if value < Self::SIZE {
Ok(Self{
inner: (
2025-09-23 22:20:18 +09:00
Single::try_from(u16::try_from(value/(Single::SIZE as u32)).unwrap())?,
Single::try_from(u16::try_from(value % (Single::SIZE as u32)).unwrap())?
2025-09-13 08:39:06 +09:00
)})
} else {
2025-09-13 12:29:59 +09:00
Err(Error::OutsideOfRange{
expected: Self::SIZE as u64,
found: value as u64
2025-09-13 12:29:59 +09:00
})
2025-09-13 08:39:06 +09:00
}
}
}
impl From<Double> for u32 {
fn from(value: Double) -> Self {
u32::from(u16::from(value.inner.0)) * u32::from(Single::SIZE) + u32::from(u16::from(value.inner.1))
2025-09-13 08:39:06 +09:00
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_random<R>(rand: &mut R)
where
R: Rng
{
2025-09-23 22:20:18 +09:00
let id: Double = rand.r#gen();
2025-09-13 12:29:59 +09:00
assert!(id.is_valid());
2025-09-23 22:20:18 +09:00
assert_eq!(id,Double::from_str(&id.to_string()).unwrap());
assert_eq!(id, Double::try_from(u32::from(id)).unwrap())
2025-09-13 08:39:06 +09:00
}
#[test]
fn random_x10() {
let mut rng = rand::thread_rng();
for _ in 0..10 {
assert_random(&mut rng);
}
}
}