diff --git a/tripod-id/src/double.rs b/tripod-id/src/double.rs index 45a0bcc..4723ece 100644 --- a/tripod-id/src/double.rs +++ b/tripod-id/src/double.rs @@ -10,8 +10,8 @@ pub struct Double{ } impl TripodId for Double{ - type SizeType = u32; - const SIZE: Self::SizeType = (Single::SIZE as u32).pow(2); + type Integer = u32; + const CAPACITY: Self::Integer = (Single::CAPACITY as u32).pow(2); /// ``` /// use tripod_id::{TripodId, Double}; /// use std::str::FromStr; @@ -35,8 +35,8 @@ impl TripodId for Double{ }; #[cfg(test)] - fn is_valid(&self) -> bool { - self.inner.0.is_valid() && self.inner.1.is_valid() && (u32::from(*self) < Self::SIZE) + fn validate_inner(self) -> bool { + self.inner.0.validate_inner() && self.inner.1.validate_inner() && (u32::from(self) < Self::CAPACITY) } } @@ -90,15 +90,15 @@ impl TryFrom for Double { type Error = Error; fn try_from(value: u32) -> Result { - if value < Self::SIZE { + if value < Self::CAPACITY { Ok(Self{ inner: ( - Single::try_from(u16::try_from(value/(Single::SIZE as u32)).unwrap())?, - Single::try_from(u16::try_from(value % (Single::SIZE as u32)).unwrap())? + Single::try_from(u16::try_from(value/(Single::CAPACITY as u32)).unwrap())?, + Single::try_from(u16::try_from(value % (Single::CAPACITY as u32)).unwrap())? )}) } else { Err(Error::OutsideOfRange{ - expected: Self::SIZE as u64, + expected: Self::CAPACITY as u64, found: value as u64 }) } @@ -107,29 +107,61 @@ impl TryFrom for Double { impl From 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)) + u32::from(u16::from(value.inner.0)) * u32::from(Single::CAPACITY) + u32::from(u16::from(value.inner.1)) } } + +impl PartialEq for Double { + fn eq(&self, other: &u32) -> bool { + &u32::from(*self) == other + } +} + +impl PartialEq for Double { + fn eq(&self, other: &String) -> bool { + match Self::from_str(other) { + Ok(x) => *self == x, + Err(_) => false + } + } +} + + #[cfg(test)] mod tests { - use super::*; +use crate::tests::{assert_id_eq_int, assert_id_eq_str}; - fn assert_random(rand: &mut R) - where - R: Rng - { - let id: Double = rand.r#gen(); - assert!(id.is_valid()); - assert_eq!(id,Double::from_str(&id.to_string()).unwrap()); - assert_eq!(id, Double::try_from(u32::from(id)).unwrap()) - } + use super::*; #[test] - fn random_x10() { + fn nil() { + assert!(Double::NIL.validate_all().unwrap()); + assert_eq!(Double::NIL, 0); + assert_eq!(Double::NIL, "000000".to_string()); + assert_eq!(Double::NIL, "000-000".to_string()); + + } + + #[test] + fn max() { + assert!(Double::MAX.validate_all().unwrap()); + assert_eq!(Double::MAX, Double::CAPACITY-1); + assert_eq!(Double::MAX, "zzzzzz".to_string()); + assert_eq!(Double::MAX, "ZZZ-ZZZ".to_string()); + } + + #[test] + #[should_panic] + fn over_sized() { + Double::try_from(Double::CAPACITY).unwrap(); + } + + #[test] + fn random() { let mut rng = rand::thread_rng(); for _ in 0..10 { - assert_random(&mut rng); + let id: Double = rng.r#gen(); + assert!(id.validate_all().unwrap()); } - } } \ No newline at end of file diff --git a/tripod-id/src/lib.rs b/tripod-id/src/lib.rs index 6d9da23..9d2d5ee 100644 --- a/tripod-id/src/lib.rs +++ b/tripod-id/src/lib.rs @@ -8,6 +8,8 @@ mod rusqlite; #[cfg(feature="serde")] mod serde; +use std::{fmt::Display, str::FromStr}; + pub use single::*; pub use double::*; pub use triple::*; @@ -18,39 +20,63 @@ pub mod prost; #[cfg(feature="prost")] pub use prost::{ SingleMessage, DoubleMessage, TripleMessage }; -pub trait TripodId { - type SizeType; +pub trait TripodId: Copy + Display + TryFrom + FromStr + PartialEq { + type Integer: From; const NIL: Self; const MAX: Self; - const SIZE: Self::SizeType; + const CAPACITY: Self::Integer; #[cfg(test)] - fn is_valid(&self) -> bool; + fn validate_inner(self) -> bool; + + #[cfg(test)] + fn validate_string_convertion(self) -> Result { + Ok(self == Self::from_str(&self.to_string())?) + } + + #[cfg(test)] + fn validate_integer_conversion(self) -> Result { + Ok(self == Self::try_from(Self::Integer::from(self))?) + } + + #[cfg(test)] + fn validate_all(self) -> Result { + Ok(self.validate_inner() + && self.validate_string_convertion()? + && self.validate_integer_conversion()? + ) + } } #[cfg(test)] mod tests { use std::{fmt::Display, fmt::Debug, str::FromStr}; + #[cfg(feature="prost")] +use crate::prost::TrypodIdMessage; + use super::*; #[cfg(feature="prost")] - fn assert_prost(id: T) where - T: TripodId + Debug + Display + FromStr + PartialEq + TryFrom + Copy, - I: From { - use crate::SingleMessage; - let message = SingleMessage::from(*id); - assert_eq!(message.is_valid()); - let result = Single::try_from(message).unwrap(); - assert_eq!(id, result); + pub fn assert_valid_message(id: &T) where + T: TripodId + Debug + Display + FromStr + PartialEq + TryFrom + Copy, + M: TrypodIdMessage + From + { + let message = M::from(*id); + assert!(message.is_valid()); + assert_eq!(*id, T::try_from(message).unwrap()); } - fn assert_id (id: T) where - T: TripodId + Debug + Display + FromStr + PartialEq + TryFrom + Copy, - I: From + pub fn assert_id_eq_int (id: T, int: I ) where + T: TripodId + Debug + PartialEq + TryFrom + Copy, + I: From + PartialEq + Debug + Copy { - assert!(id.is_valid()); - let s = id.to_string(); - assert_eq!(id,T::from_str(&s).unwrap()); - let i = T::SizeType::from(id); - assert_eq!(id, T::try_from(i).unwrap()); + assert_eq!(id, T::try_from(int).unwrap()); + assert_eq!(I::from(id), int); } + + pub fn assert_id_eq_str (id: T, code: &str ) where + T: TripodId + Debug + Display + FromStr + PartialEq + Copy, + { + assert_eq!(id, T::from_str(code).unwrap()); + } + } \ No newline at end of file diff --git a/tripod-id/src/prost/double.rs b/tripod-id/src/prost/double.rs index 98427fb..06f977a 100644 --- a/tripod-id/src/prost/double.rs +++ b/tripod-id/src/prost/double.rs @@ -12,7 +12,7 @@ impl Double { pub fn is_valid(&self) -> bool { use crate::TripodId; - self.id < u32::from(crate::Double::SIZE) + self.id < u32::from(crate::Double::CAPACITY) } } diff --git a/tripod-id/src/prost/single.rs b/tripod-id/src/prost/single.rs index 6a7b3a2..5aa618c 100644 --- a/tripod-id/src/prost/single.rs +++ b/tripod-id/src/prost/single.rs @@ -12,7 +12,7 @@ impl Single { pub fn is_valid(&self) -> bool { use crate::TripodId; - self.id < u32::from(crate::Single::SIZE) + self.id < u32::from(crate::Single::CAPACITY) } } @@ -29,7 +29,7 @@ impl TryFrom for crate::Single { fn try_from(value: Single) -> Result { Self::try_from( u16::try_from(value.id).or(Err(Error::OutsideOfRange { - expected: u64::from(crate::Single::SIZE), + expected: u64::from(crate::Single::CAPACITY), found: u64::from(value.id) }))? ) diff --git a/tripod-id/src/prost/triple.rs b/tripod-id/src/prost/triple.rs index 0e92bc2..f807c48 100644 --- a/tripod-id/src/prost/triple.rs +++ b/tripod-id/src/prost/triple.rs @@ -12,7 +12,7 @@ impl Triple { pub fn is_valid(&self) -> bool { use crate::TripodId; - self.id < crate::Triple::SIZE + self.id < crate::Triple::CAPACITY } } diff --git a/tripod-id/src/single.rs b/tripod-id/src/single.rs index 016d856..bac434f 100644 --- a/tripod-id/src/single.rs +++ b/tripod-id/src/single.rs @@ -108,16 +108,10 @@ pub struct Single{ impl TripodId for Single { - type SizeType = u16; - const SIZE: Self::SizeType = CUBED_BASE; + type Integer = u16; + const CAPACITY: Self::Integer = CUBED_BASE; + - /// ``` - /// use tripod_id::{Single, TripodId}; - /// use std::str::FromStr; - /// - /// assert_eq!(Single::NIL, Single::from_str("000").unwrap()); - /// assert_eq!(Single::NIL, Single::try_from(0).unwrap()); - /// ``` const NIL: Single = Single{ inner: 0 }; @@ -130,12 +124,12 @@ impl TripodId for Single { /// assert_eq!(Single::MAX, Single::try_from(35936).unwrap()); /// ``` const MAX: Single = Single{ - inner: Self::SIZE-1 + inner: Self::CAPACITY-1 }; #[cfg(test)] - fn is_valid(&self) -> bool { - self.inner < Self::SIZE + fn validate_inner(self) -> bool { + self.inner < Self::CAPACITY } } @@ -158,7 +152,7 @@ impl FromStr for Single { impl Distribution for Standard { fn sample(&self, rng: &mut R) -> Single { Single { - inner: rng.gen_range(0..Single::SIZE) + inner: rng.gen_range(0..Single::CAPACITY) } } } @@ -167,11 +161,11 @@ impl TryFrom for Single { type Error = Error; fn try_from(value: u16) -> Result { - if value < Self::SIZE { + if value < Self::CAPACITY { Ok(Self{inner: value}) } else { Err(Error::OutsideOfRange{ - expected: Self::SIZE as u64, + expected: Self::CAPACITY as u64, found: value as u64 }) } @@ -184,42 +178,57 @@ impl From for u16 { } } +impl PartialEq for Single { + fn eq(&self, other: &u16) -> bool { + &u16::from(*self) == other + } +} + +impl PartialEq for Single { + fn eq(&self, other: &String) -> bool { + match Self::from_str(other) { + Ok(x) => *self == x, + Err(_) => false + } + } +} + #[cfg(test)] mod tests { + use crate::tests::{assert_id_eq_int, assert_id_eq_str}; + use super::*; - - #[cfg(feature="prost")] - fn assert_prost(id: Single) { - use crate::SingleMessage; - let message = SingleMessage::from(*id); - assert_eq!(message.is_valid()); - let result = Single::try_from(message).unwrap(); - assert_eq!(id, result); - } - - fn assert_id(id: Single) { - assert!(id.is_valid()); - let s = id.to_string(); - assert_eq!(id,Single::from_str(&s).unwrap()); - let i = u16::from(id); - assert_eq!(id, Single::try_from(i).unwrap()); - } - - fn assert_random(rand: &mut R) - where - R: Rng - { - let chunk: Single = rand.r#gen(); - - } #[test] - fn random_x10() { + fn nil() { + assert!(Single::NIL.validate_all().unwrap()); + assert_eq!(Single::NIL, 0); + assert_eq!(Single::NIL, "000".to_string()); + } + + #[test] + fn max() { + assert!(Single::MAX.validate_all().unwrap()); + assert_eq!(Single::MAX, Single::CAPACITY-1); + assert_eq!(Single::MAX, "zzz".to_string()); + assert_eq!(Single::MAX, "ZZZ".to_string()); + } + + #[test] + #[should_panic] + fn over_sized() { + Single::try_from(Single::CAPACITY).unwrap(); + } + + #[test] + fn random() { let mut rng = rand::thread_rng(); for _ in 0..10 { - assert_random(&mut rng); + let single: Single = rng.r#gen(); + assert!(single.validate_all().unwrap()); } - } + + } \ No newline at end of file diff --git a/tripod-id/src/triple.rs b/tripod-id/src/triple.rs index d72130b..35644b2 100644 --- a/tripod-id/src/triple.rs +++ b/tripod-id/src/triple.rs @@ -12,8 +12,8 @@ pub struct Triple { } impl TripodId for Triple{ - type SizeType = u64; - const SIZE: Self::SizeType = (Single::SIZE as u64).pow(3); + type Integer = u64; + const CAPACITY: Self::Integer = (Single::CAPACITY as u64).pow(3); /// ``` /// use tripod_id::{TripodId, Triple}; /// use std::str::FromStr; @@ -37,8 +37,11 @@ impl TripodId for Triple{ }; #[cfg(test)] - fn is_valid(&self) -> bool { - self.inner.0.is_valid() && self.inner.1.is_valid() && self.inner.2.is_valid() && (u64::from(*self) < Self::SIZE) + fn validate_inner(self) -> bool { + self.inner.0.validate_inner() + && self.inner.1.validate_inner() + && self.inner.2.validate_inner() + && (u64::from(self) < Self::CAPACITY) } } @@ -97,16 +100,16 @@ impl TryFrom for Triple { type Error = Error; fn try_from(value: u64) -> Result { - if value < Self::SIZE { + if value < Self::CAPACITY { Ok(Self{ inner: ( - Single::try_from(u16::try_from(value / (Double::SIZE as u64)).unwrap())?, - Single::try_from(u16::try_from((value % (Double::SIZE as u64)) /(Single::SIZE as u64)).unwrap())?, - Single::try_from(u16::try_from(value % (Single::SIZE as u64)).unwrap())? + Single::try_from(u16::try_from(value / (Double::CAPACITY as u64)).unwrap())?, + Single::try_from(u16::try_from((value % (Double::CAPACITY as u64)) /(Single::CAPACITY as u64)).unwrap())?, + Single::try_from(u16::try_from(value % (Single::CAPACITY as u64)).unwrap())? )}) } else { Err(Error::OutsideOfRange{ - expected: Self::SIZE as u64, + expected: Self::CAPACITY as u64, found: value as u64 }) } @@ -115,31 +118,62 @@ impl TryFrom for Triple { impl From for u64 { fn from(value: Triple) -> Self { - (u16::from(value.inner.0) as u64) * (Double::SIZE as u64) - + (u16::from(value.inner.1) as u64) * (Single::SIZE as u64) + (u16::from(value.inner.0) as u64) * (Double::CAPACITY as u64) + + (u16::from(value.inner.1) as u64) * (Single::CAPACITY as u64) + (u16::from(value.inner.2) as u64) } } +impl PartialEq for Triple { + fn eq(&self, other: &u64) -> bool { + &u64::from(*self) == other + } +} + +impl PartialEq for Triple { + fn eq(&self, other: &String) -> bool { + match Self::from_str(other) { + Ok(x) => *self == x, + Err(_) => false + } + } +} + + #[cfg(test)] mod tests { - use super::*; +use crate::tests::{assert_id_eq_int, assert_id_eq_str}; - fn assert_random(rand: &mut R) - where - R: Rng - { - let id: Triple = rand.r#gen(); - assert!(id.is_valid()); - assert_eq!(id, Triple::from_str(&id.to_string()).unwrap()); - assert_eq!(id, Triple::try_from(u64::from(id)).unwrap()); - } + use super::*; #[test] - fn random_x10() { + fn nil() { + assert!(Triple::NIL.validate_all().unwrap()); + assert_eq!(Triple::NIL, 0); + assert_eq!(Triple::NIL, "000000000".to_string()); + assert_eq!(Triple::NIL, "000-000-000".to_string()); + + } + + #[test] + fn max() { + assert!(Triple::MAX.validate_all().unwrap()); + assert_eq!(Triple::MAX, Triple::CAPACITY-1); + assert_eq!(Triple::MAX, "zzzzzzzzz".to_string()); + assert_eq!(Triple::MAX, "ZZZ-ZZZ-ZZZ".to_string()); + } + + #[test] + #[should_panic] + fn over_sized() { + Triple::try_from(Triple::CAPACITY).unwrap(); + } + + #[test] + fn random() { let mut rng = rand::thread_rng(); for _ in 0..10 { - assert_random(&mut rng); + let id: Triple = rng.r#gen(); + assert!(id.validate_all().unwrap()); } - } } \ No newline at end of file