rasn_smi/
v1.rs

1//! Version 1 (RFC 1155)
2
3use rasn::{
4    error::EncodeError,
5    types::{
6        Constraints, FixedOctetString, Identifier, Integer, ObjectIdentifier, OctetString, Oid, Tag,
7    },
8    AsnType, Decode, Encode,
9};
10
11pub const INTERNET: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET;
12pub const DIRECTORY: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_DIRECTORY;
13pub const MGMT: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_MGMT;
14pub const EXPERIMENTAL: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_EXPERIMENTAL;
15pub const PRIVATE: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE;
16pub const ENTERPRISES: &Oid = Oid::ISO_IDENTIFIED_ORGANISATION_DOD_INTERNET_PRIVATE_ENTERPRISES;
17
18pub type ObjectName = ObjectIdentifier;
19
20#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
21#[rasn(choice)]
22pub enum ObjectSyntax {
23    Simple(SimpleSyntax),
24    ApplicationWide(ApplicationSyntax),
25}
26
27#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
28#[rasn(choice)]
29pub enum SimpleSyntax {
30    Number(Integer),
31    String(OctetString),
32    Object(ObjectIdentifier),
33    Empty,
34}
35
36#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
37#[rasn(choice)]
38pub enum ApplicationSyntax {
39    Address(NetworkAddress),
40    Counter(Counter),
41    Gauge(Gauge),
42    Ticks(TimeTicks),
43    Arbitrary(Opaque),
44}
45
46#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
47#[rasn(choice)]
48pub enum NetworkAddress {
49    Internet(IpAddress),
50}
51
52#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
53#[rasn(delegate, tag(application, 0))]
54pub struct IpAddress(pub FixedOctetString<4>);
55
56#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
57#[rasn(delegate, tag(application, 1))]
58pub struct Counter(pub u32);
59
60#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
61#[rasn(delegate, tag(application, 2))]
62pub struct Gauge(pub u32);
63
64#[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
65#[rasn(delegate, tag(application, 3))]
66pub struct TimeTicks(pub u32);
67
68/// A wrapper around arbitrary ASN.1 syntax, encoded in Basic Encoding Rules,
69/// this type is not typically useful on its own, and should decoded into its
70/// inner type when possible.
71#[derive(AsnType, Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)]
72#[rasn(tag(application, 4))]
73pub struct Opaque(alloc::vec::Vec<u8>);
74
75/// Helper trait for wrapping any valid ASN.1 type in an `Opaque` struct which
76/// first encodes the data into Basic Encoding Rules.
77pub trait ToOpaque {
78    fn to_opaque(&self) -> Result<Opaque, EncodeError>;
79}
80
81impl<T: Encode> ToOpaque for T {
82    fn to_opaque(&self) -> Result<Opaque, EncodeError> {
83        rasn::ber::encode(self).map(Opaque)
84    }
85}
86
87impl AsRef<[u8]> for Opaque {
88    fn as_ref(&self) -> &[u8] {
89        self.0.as_ref()
90    }
91}
92
93impl Decode for Opaque {
94    fn decode_with_tag_and_constraints<D: rasn::Decoder>(
95        decoder: &mut D,
96        tag: Tag,
97        constraints: Constraints,
98    ) -> Result<Self, D::Error> {
99        decoder.decode_octet_string(tag, constraints).map(Self)
100    }
101}
102
103impl Encode for Opaque {
104    fn encode_with_tag_and_constraints<'encoder, EN: rasn::Encoder<'encoder>>(
105        &self,
106        encoder: &mut EN,
107        tag: Tag,
108        constraints: Constraints,
109        identifier: Identifier,
110    ) -> Result<(), EN::Error> {
111        encoder
112            .encode_octet_string(tag, constraints, &self.0, identifier)
113            .map(drop)
114    }
115}
116
117/// The message was valid SMI but was not the variant we expected.
118pub struct InvalidVariant;
119
120impl core::fmt::Display for InvalidVariant {
121    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122        f.write_str("Message was valid SMI but was not the variant we expected")
123    }
124}
125
126from_impls! {
127    // -> ObjectSyntax
128    impl SimpleSyntax => ObjectSyntax: (value) -> ObjectSyntax::Simple(value);
129    impl ApplicationSyntax => ObjectSyntax: (value) -> ObjectSyntax::ApplicationWide(value);
130    impl Integer => ObjectSyntax: (value) -> SimpleSyntax::Number(value).into();
131    impl u8 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
132    impl u16 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
133    impl u32 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
134    impl u64 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
135    impl u128 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
136    impl i8 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
137    impl i16 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
138    impl i32 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
139    impl i64 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
140    impl i128 => ObjectSyntax: (value) -> SimpleSyntax::Number(value.into()).into();
141    impl OctetString => ObjectSyntax:  (value) -> SimpleSyntax::String(value).into();
142    impl ObjectIdentifier => ObjectSyntax:  (value) -> SimpleSyntax::Object(value).into();
143    impl NetworkAddress => ObjectSyntax:  (value) -> ApplicationSyntax::Address(value).into();
144    impl Counter => ObjectSyntax:  (value) -> ApplicationSyntax::Counter(value).into();
145    impl Gauge => ObjectSyntax:  (value) -> ApplicationSyntax::Gauge(value).into();
146    impl TimeTicks => ObjectSyntax: (value) -> ApplicationSyntax::Ticks(value).into();
147    impl Opaque => ObjectSyntax: (value) -> ApplicationSyntax::Arbitrary(value).into();
148    impl IpAddress => ObjectSyntax: (value) -> ApplicationSyntax::Address(NetworkAddress::Internet(value)).into();
149    // -> SimpleSyntax
150    impl Integer => SimpleSyntax: (value) -> SimpleSyntax::Number(value);
151    impl u8 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
152    impl u16 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
153    impl u32 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
154    impl u64 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
155    impl u128 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
156    impl i8 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
157    impl i16 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
158    impl i32 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
159    impl i64 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
160    impl i128 => SimpleSyntax: (value) -> SimpleSyntax::Number(value.into());
161    impl OctetString => SimpleSyntax:  (value) -> SimpleSyntax::String(value);
162    impl ObjectIdentifier => SimpleSyntax:  (value) -> SimpleSyntax::Object(value);
163    // -> ApplicationSyntax
164    impl NetworkAddress => ApplicationSyntax:  (value) -> ApplicationSyntax::Address(value);
165    impl Counter => ApplicationSyntax:  (value) -> ApplicationSyntax::Counter(value);
166    impl Gauge => ApplicationSyntax:  (value) -> ApplicationSyntax::Gauge(value);
167    impl TimeTicks => ApplicationSyntax: (value) -> ApplicationSyntax::Ticks(value);
168    impl Opaque => ApplicationSyntax: (value) -> ApplicationSyntax::Arbitrary(value);
169    impl IpAddress => ApplicationSyntax: (value) -> ApplicationSyntax::Address(NetworkAddress::Internet(value));
170}
171
172macro_rules! try_from_impls_v1 {
173    ($(impl $name:ty => $pattern:pat => $return:expr);+ $(;)?) => {
174        $(
175            impl core::convert::TryFrom<$crate::v1::ObjectSyntax> for $name {
176                type Error = $crate::v1::InvalidVariant;
177                fn try_from(value: $crate::v1::ObjectSyntax) -> Result<Self, Self::Error> {
178                    Ok(match value {
179                        $pattern => $return,
180                        _ => return Err($crate::v1::InvalidVariant),
181                    })
182                }
183            }
184        )+
185    }
186}
187
188try_from_impls_v1! {
189    impl OctetString => ObjectSyntax::Simple(SimpleSyntax::String(value)) => value;
190    impl Integer => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value;
191    impl u8 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
192    impl u16 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
193    impl u32 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
194    impl u64 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
195    impl u128 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
196    impl i8 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
197    impl i16 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
198    impl i32 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
199    impl i64 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
200    impl i128 => ObjectSyntax::Simple(SimpleSyntax::Number(value)) => value.try_into().map_err(|_| InvalidVariant)?;
201    impl ObjectIdentifier => ObjectSyntax::Simple(SimpleSyntax::Object(value)) => value;
202    impl () => ObjectSyntax::Simple(SimpleSyntax::Empty) => ();
203    impl NetworkAddress => ObjectSyntax::ApplicationWide(ApplicationSyntax::Address(value)) => value;
204    impl Counter => ObjectSyntax::ApplicationWide(ApplicationSyntax::Counter(value)) => value;
205    impl Gauge => ObjectSyntax::ApplicationWide(ApplicationSyntax::Gauge(value)) => value;
206    impl TimeTicks => ObjectSyntax::ApplicationWide(ApplicationSyntax::Ticks(value)) => value;
207    impl Opaque => ObjectSyntax::ApplicationWide(ApplicationSyntax::Arbitrary(value)) => value;
208    impl IpAddress => ObjectSyntax::ApplicationWide(ApplicationSyntax::Address(NetworkAddress::Internet(value))) => value;
209}