use core::hash::Hash;
use super::Error;
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TokenLength {
Zero = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
}
impl TryFrom<u8> for TokenLength {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(TokenLength::Zero),
1 => Ok(TokenLength::One),
2 => Ok(TokenLength::Two),
3 => Ok(TokenLength::Three),
4 => Ok(TokenLength::Four),
5 => Ok(TokenLength::Five),
6 => Ok(TokenLength::Six),
7 => Ok(TokenLength::Seven),
8 => Ok(TokenLength::Eight),
_ => Err(Error::TokenLength),
}
}
}
#[allow(clippy::from_over_into)] impl Into<u8> for TokenLength {
fn into(self) -> u8 {
self as u8
}
}
impl TryFrom<usize> for TokenLength {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
if value > 255 {
Err(Error::TokenLength)
} else {
Self::try_from(value as u8)
}
}
}
#[allow(clippy::from_over_into)] impl Into<usize> for TokenLength {
fn into(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy)]
pub struct Token {
pub(crate) bytes: [u8; 8],
pub(crate) length: TokenLength,
}
impl Default for Token {
fn default() -> Self {
Self {
bytes: [0_u8; 8],
length: TokenLength::Zero,
}
}
}
impl Token {
pub(crate) fn try_new<RNG: embedded_hal::blocking::rng::Read>(
length: TokenLength,
rng: &mut RNG,
) -> Result<Self, RNG::Error> {
let mut token = Token {
length,
..Default::default()
};
rng.read(&mut token.bytes[..token.length as usize])?;
Ok(token)
}
}
impl TryFrom<&[u8]> for Token {
type Error = Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let mut token = Token {
bytes: [0_u8; 8],
length: (value.len() as u8).try_into()?,
};
token.bytes[..token.length.into()].copy_from_slice(value);
Ok(token)
}
}
impl PartialEq for Token {
fn eq(&self, other: &Self) -> bool {
self.bytes[..self.length.into()] == other.bytes[..other.length.into()]
}
}
impl Eq for Token {}
impl PartialOrd for Token {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Token {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
if self.length != other.length {
return self.length.cmp(&other.length);
}
self.bytes[..self.length.into()].cmp(&other.bytes[..self.length.into()])
}
}
impl Hash for Token {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.bytes[..self.length.into()].hash(state)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partial_eq() {
let a = Token {
bytes: [0; 8],
length: 8_u8.try_into().unwrap(),
};
let b = Token {
bytes: [1; 8],
length: 8_u8.try_into().unwrap(),
};
let c = Token {
bytes: [0; 8],
length: 4_u8.try_into().unwrap(),
};
assert_eq!(a, a); assert_ne!(a, b); assert_ne!(a, c); assert_ne!(b, c); }
}