use failure::{bail, Error};
use serde::{
de::{self, Deserialize, Deserializer, Visitor},
ser::{Serialize, Serializer},
};
use std::{
fmt::{self, Display},
str::FromStr,
};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Type {
Opaque = 0x01,
AuthenticationKey = 0x02,
AsymmetricKey = 0x03,
WrapKey = 0x04,
HmacKey = 0x05,
Template = 0x06,
OtpAeadKey = 0x07,
}
impl Type {
pub fn from_u8(byte: u8) -> Result<Self, Error> {
Ok(match byte {
0x01 => Type::Opaque,
0x02 => Type::AuthenticationKey,
0x03 => Type::AsymmetricKey,
0x04 => Type::WrapKey,
0x05 => Type::HmacKey,
0x06 => Type::Template,
0x07 => Type::OtpAeadKey,
_ => bail!("invalid object type: {}", byte),
})
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Type::Opaque => "opaque",
Type::AuthenticationKey => "authentication-key",
Type::AsymmetricKey => "asymmetric-key",
Type::WrapKey => "wrap-key",
Type::HmacKey => "hmac-key",
Type::Template => "template",
Type::OtpAeadKey => "otp-aead-key",
};
write!(f, "{}", s)
}
}
impl FromStr for Type {
type Err = ();
fn from_str(s: &str) -> Result<Type, ()> {
Ok(match s {
"opaque" => Type::Opaque,
"authentication-key" => Type::AuthenticationKey,
"asymmetric-key" => Type::AsymmetricKey,
"wrap-key" => Type::WrapKey,
"hmac-key" => Type::HmacKey,
"template" => Type::Template,
"otp-aead-key" => Type::OtpAeadKey,
_ => return Err(()),
})
}
}
impl Serialize for Type {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u8(self.to_u8())
}
}
impl<'de> Deserialize<'de> for Type {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Type, D::Error> {
struct TypeVisitor;
impl<'de> Visitor<'de> for TypeVisitor {
type Value = Type;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an unsigned byte between 0x01 and 0x07")
}
fn visit_u8<E: de::Error>(self, value: u8) -> Result<Type, E> {
Type::from_u8(value).or_else(|e| Err(E::custom(format!("{}", e))))
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Type, E> {
assert!(value < 255);
Type::from_u8(value as u8).or_else(|e| Err(E::custom(format!("{}", e))))
}
}
deserializer.deserialize_u8(TypeVisitor)
}
}