use nom::IResult;
use nom::number::complete::be_u8;
use std::fmt;
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct CurveType(u8);
#[allow(non_upper_case_globals)]
impl CurveType {
pub const ExplicitPrime: Self = Self(1);
pub const ExplicitChar2: Self = Self(2);
pub const NamedCurve: Self = Self(3);
pub const fn from_u8(value: u8) -> Self {
Self(value)
}
pub const fn as_u8(&self) -> u8 {
self.0
}
const fn is_unknown(&self) -> bool {
!matches!(*self, Self(1..=3))
}
pub fn parse(input: &[u8]) -> IResult<&[u8], CurveType> {
let (input, value) = be_u8(input)?;
Ok((input, CurveType::from_u8(value)))
}
}
impl fmt::Debug for CurveType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_unknown() {
return f.debug_tuple("Unknown").field(&self.0).finish();
}
let name = match *self {
CurveType::ExplicitPrime => "ExplicitPrime",
CurveType::ExplicitChar2 => "ExplicitChar2",
CurveType::NamedCurve => "NamedCurve",
_ => unreachable!("known DTLS 1.2 curve type missing Debug label"),
};
f.write_str(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn curve_type_newtype_shape() {
assert_eq!(std::mem::size_of::<CurveType>(), 1);
}
#[test]
fn curve_type_wire_roundtrip() {
for curve_type in [
CurveType::ExplicitPrime,
CurveType::ExplicitChar2,
CurveType::NamedCurve,
] {
assert_eq!(CurveType::from_u8(curve_type.as_u8()), curve_type);
assert!(!curve_type.is_unknown());
}
let unknown = CurveType::from_u8(0xFF);
assert_eq!(unknown.as_u8(), 0xFF);
assert!(unknown.is_unknown());
}
#[test]
fn curve_type_debug_stays_enum_like() {
assert_eq!(format!("{:?}", CurveType::NamedCurve), "NamedCurve");
assert_eq!(format!("{:?}", CurveType::from_u8(0xFF)), "Unknown(255)");
}
}