use rasn::{
error::EncodeError,
types::{Constraints, FixedOctetString, Integer, ObjectIdentifier, OctetString, Oid},
AsnType, Decode, Encode, Tag,
};
pub const INTERNET: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET;
pub const DIRECTORY: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_DIRECTORY;
pub const MGMT: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_MGMT;
pub const EXPERIMENTAL: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_EXPERIMENTAL;
pub const PRIVATE: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE;
pub const ENTERPRISES: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES;
pub type ObjectName = ObjectIdentifier;
#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(choice)]
pub enum ObjectSyntax {
Simple(SimpleSyntax),
ApplicationWide(ApplicationSyntax),
}
#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(choice)]
pub enum SimpleSyntax {
Number(Integer),
String(OctetString),
Object(ObjectIdentifier),
Empty,
}
#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(choice)]
pub enum ApplicationSyntax {
Address(NetworkAddress),
Counter(Counter),
Gauge(Gauge),
Ticks(TimeTicks),
Arbitrary(Opaque),
}
#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(choice)]
pub enum NetworkAddress {
Internet(IpAddress),
}
#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(delegate, tag(application, 0))]
pub struct IpAddress(pub FixedOctetString<4>);
#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(delegate, tag(application, 1))]
pub struct Counter(pub u32);
#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(delegate, tag(application, 2))]
pub struct Gauge(pub u32);
#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[rasn(delegate, tag(application, 3))]
pub struct TimeTicks(pub u32);
#[derive(AsnType, Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
#[rasn(tag(application, 4))]
pub struct Opaque(alloc::vec::Vec<u8>);
pub trait ToOpaque {
fn to_opaque(&self) -> Result<Opaque, EncodeError>;
}
impl<T: Encode> ToOpaque for T {
fn to_opaque(&self) -> Result<Opaque, EncodeError> {
rasn::ber::encode(self).map(Opaque)
}
}
impl AsRef<[u8]> for Opaque {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Decode for Opaque {
fn decode_with_tag_and_constraints<D: rasn::Decoder>(
decoder: &mut D,
tag: Tag,
constraints: Constraints,
) -> Result<Self, D::Error> {
decoder.decode_octet_string(tag, constraints).map(Self)
}
}
impl Encode for Opaque {
fn encode_with_tag_and_constraints<EN: rasn::Encoder>(
&self,
encoder: &mut EN,
tag: Tag,
constraints: Constraints,
) -> Result<(), EN::Error> {
encoder
.encode_octet_string(tag, constraints, &self.0)
.map(drop)
}
}
pub struct InvalidVariant;
impl core::fmt::Display for InvalidVariant {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("Message was valid SMI but was not the variant we expected")
}
}
from_impls! {
impl SimpleSyntax => ObjectSyntax: (value) -> ObjectSyntax::Simple(value);
impl ApplicationSyntax => ObjectSyntax: (value) -> ObjectSyntax::ApplicationWide(value);
impl Integer => ObjectSyntax: (value) -> SimpleSyntax::Number(value).into();
impl u8 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl u16 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl u32 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl u64 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl u128 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl i8 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl i16 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl i32 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl i64 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl i128 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
impl OctetString => ObjectSyntax: (value) -> SimpleSyntax::String(value).into();
impl ObjectIdentifier => ObjectSyntax: (value) -> SimpleSyntax::Object(value).into();
impl NetworkAddress => ObjectSyntax: (value) -> ApplicationSyntax::Address(value).into();
impl Counter => ObjectSyntax: (value) -> ApplicationSyntax::Counter(value).into();
impl Gauge => ObjectSyntax: (value) -> ApplicationSyntax::Gauge(value).into();
impl TimeTicks => ObjectSyntax: (value) -> ApplicationSyntax::Ticks(value).into();
impl Opaque => ObjectSyntax: (value) -> ApplicationSyntax::Arbitrary(value).into();
impl IpAddress => ObjectSyntax: (value) -> ApplicationSyntax::Address(NetworkAddress::Internet(value)).into();
impl Integer => SimpleSyntax: (value) -> SimpleSyntax::Number(value);
impl u8 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl u16 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl u32 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl u64 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl u128 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl i8 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl i16 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl i32 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl i64 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl i128 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
impl OctetString => SimpleSyntax: (value) -> SimpleSyntax::String(value);
impl ObjectIdentifier => SimpleSyntax: (value) -> SimpleSyntax::Object(value);
impl NetworkAddress => ApplicationSyntax: (value) -> ApplicationSyntax::Address(value);
impl Counter => ApplicationSyntax: (value) -> ApplicationSyntax::Counter(value);
impl Gauge => ApplicationSyntax: (value) -> ApplicationSyntax::Gauge(value);
impl TimeTicks => ApplicationSyntax: (value) -> ApplicationSyntax::Ticks(value);
impl Opaque => ApplicationSyntax: (value) -> ApplicationSyntax::Arbitrary(value);
impl IpAddress => ApplicationSyntax: (value) -> ApplicationSyntax::Address(NetworkAddress::Internet(value));
}
macro_rules! try_from_impls_v1 {
($(impl $name:ty => $pattern:pat => $return:expr);+ $(;)?) => {
$(
impl core::convert::TryFrom<$crate::v1::ObjectSyntax> for $name {
type Error = $crate::v1::InvalidVariant;
fn try_from(value: $crate::v1::ObjectSyntax) -> Result<Self, Self::Error> {
Ok(match value {
$pattern => $return,
_ => return Err($crate::v1::InvalidVariant),
})
}
}
)+
}
}
try_from_impls_v1! {
impl OctetString => ObjectSyntax::Simple(SimpleSyntax::String(value)) => value;
impl Integer => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value;
impl u8 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl u16 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl u32 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl u64 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl u128 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl i8 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl i16 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl i32 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl i64 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl i128 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
impl ObjectIdentifier => ObjectSyntax::Simple(SimpleSyntax::Object(value)) => value;
impl () => ObjectSyntax::Simple(SimpleSyntax::Empty) => ();
impl NetworkAddress => ObjectSyntax::ApplicationWide(ApplicationSyntax::Address(value)) => value;
impl Counter => ObjectSyntax::ApplicationWide(ApplicationSyntax::Counter(value)) => value;
impl Gauge => ObjectSyntax::ApplicationWide(ApplicationSyntax::Gauge(value)) => value;
impl TimeTicks => ObjectSyntax::ApplicationWide(ApplicationSyntax::Ticks(value)) => value;
impl Opaque => ObjectSyntax::ApplicationWide(ApplicationSyntax::Arbitrary(value)) => value;
impl IpAddress => ObjectSyntax::ApplicationWide(ApplicationSyntax::Address(NetworkAddress::Internet(value))) => value;
}