//! oid crate by turned into vendored module //! //! [Object Identifiers] are a standard of the [ITU] used to reference objects, things, and //! concepts in a globally unique way. This crate provides for data structures and methods //! to build, parse, and format OIDs. //! //! //! ## Parsing OID String Representation //! ```ignore //! use crate::oid::prelude::*; //! //! fn main() -> Result<(), ObjectIdentifierError> { //! let oid = ObjectIdentifier::try_from("0.1.2.3")?; //! Ok(()) //! } //! ``` //! //! ## Parsing OID Binary Representation //! ```ignore //! use prelude::*; //! //! fn main() -> Result<(), ObjectIdentifierError> { //! let oid = ObjectIdentifier::try_from(vec![0x00, 0x01, 0x02, 0x03])?; //! Ok(()) //! } //! ``` //! //! ## Encoding OID as String Representation //! ```ignore //! use prelude::*; //! //! fn main() -> Result<(), ObjectIdentifierError> { //! let oid = ObjectIdentifier::try_from("0.1.2.3")?; //! let oid: String = oid.into(); //! assert_eq!(oid, "0.1.2.3"); //! Ok(()) //! } //! ``` //! //! ## Encoding OID as Binary Representation //! ```ignore //! use oid::prelude::*; //! //! fn main() -> Result<(), ObjectIdentifierError> { //! let oid = ObjectIdentifier::try_from(vec![0x00, 0x01, 0x02, 0x03])?; //! let oid: Vec = oid.into(); //! assert_eq!(oid, vec![0x00, 0x01, 0x02, 0x03]); //! Ok(()) //! } //! ``` //! //! [Object Identifiers]: https://en.wikipedia.org/wiki/Object_identifier //! [ITU]: https://en.wikipedia.org/wiki/International_Telecommunications_Union use std::borrow::Cow; use crate::utils::varint::VarU128; use rkyv::ser::Serializer; use rkyv::vec::{ArchivedVec, VecResolver}; use rkyv::{Archive, Serialize}; use std::convert::TryFrom; use std::convert::TryInto; use std::fmt; use std::fmt::Formatter; use std::ops::Deref; use std::str::FromStr; type Node = u128; type VarNode = VarU128; /// Convenience module for quickly importing the public interface (e.g., `use oid::prelude::*`) pub mod prelude { pub use super::ObjectIdentifier; pub use super::ObjectIdentifierError; pub use super::ObjectIdentifierRoot::*; pub use core::convert::{TryFrom, TryInto}; } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[repr(u8)] pub enum ObjectIdentifierRoot { ItuT = 0, Iso = 1, JointIsoItuT = 2, } impl Into for ObjectIdentifierRoot { fn into(self) -> String { format!("{}", self as u8) } } impl TryFrom for ObjectIdentifierRoot { type Error = ObjectIdentifierError; fn try_from(value: u8) -> Result { match value { 0 => Ok(ObjectIdentifierRoot::ItuT), 1 => Ok(ObjectIdentifierRoot::Iso), 2 => Ok(ObjectIdentifierRoot::JointIsoItuT), _ => Err(ObjectIdentifierError::IllegalRootNode), } } } /// Object Identifier Errors #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum ObjectIdentifierError { /// Failed to parse OID due to illegal root node (must be 0-2 decimal) IllegalRootNode, /// Failed to parse OID due to illegal first node (must be 0-39 decimal) IllegalFirstChildNode, /// Failed to parse OID due to illegal child node value (except first node) IllegalChildNodeValue, } /// Object Identifier (OID) #[derive(Clone, Eq, PartialEq, Hash)] #[repr(transparent)] pub struct ObjectIdentifier<'a> { nodes: Cow<'a, [u8]>, } impl<'a> ObjectIdentifier<'a> { #[inline(always)] pub const fn new_unchecked(nodes: Cow<'a, [u8]>) -> Self { Self { nodes } } pub fn from_box(nodes: Cow<'a, [u8]>) -> Result { if nodes.len() < 1 { return Err(ObjectIdentifierError::IllegalRootNode); }; ObjectIdentifierRoot::try_from(nodes[0] / 40)?; let mut parsing_big_int = false; let mut big_int: Node = 0; for i in 1..nodes.len() { if !parsing_big_int && nodes[i] < 128 { } else { if big_int > 0 { if big_int >= Node::MAX >> 7 { return Err(ObjectIdentifierError::IllegalChildNodeValue); } big_int <<= 7; }; big_int |= (nodes[i] & !0x80) as Node; parsing_big_int = nodes[i] & 0x80 != 0; } if big_int > 0 && !parsing_big_int { big_int = 0; } } Ok(Self { nodes }) } pub fn build>( root: ObjectIdentifierRoot, first: u8, children: B, ) -> Result { if first > 40 { return Err(ObjectIdentifierError::IllegalFirstChildNode); } let children = children.as_ref(); let mut vec = Vec::with_capacity(children.len() + 1); vec.push((root as u8) * 40 + first); for child in children { let var: VarNode = child.into(); vec.extend_from_slice(var.as_bytes()) } Ok(Self { nodes: Cow::from(vec), }) } #[inline(always)] pub fn root(&self) -> Result { ObjectIdentifierRoot::try_from(self.nodes[0] / 40) } #[inline(always)] pub fn first_node(&self) -> u8 { self.nodes.as_ref()[0] % 40 } #[inline(always)] pub fn child_nodes(&self) -> &[u8] { &self.nodes[1..] } #[inline(always)] pub fn as_bytes(&self) -> &[u8] { &self.nodes } } impl Deref for ObjectIdentifier<'_> { type Target = [u8]; fn deref(&self) -> &Self::Target { &self.nodes } } impl FromStr for ObjectIdentifier<'static> { type Err = ObjectIdentifierError; fn from_str(value: &str) -> Result { let mut nodes = value.split("."); let root = nodes .next() .and_then(|n| n.parse::().ok()) .and_then(|n| n.try_into().ok()) .ok_or(ObjectIdentifierError::IllegalRootNode)?; let first = nodes .next() .and_then(|n| parse_string_first_node(n).ok()) .ok_or(ObjectIdentifierError::IllegalFirstChildNode)?; let mut children = if let (_, Some(hint)) = nodes.size_hint() { Vec::with_capacity(hint) } else { Vec::new() }; for child in nodes.map(|n| n.parse().ok()) { if let Some(c) = child { children.push(c); } else { return Err(ObjectIdentifierError::IllegalChildNodeValue); } } ObjectIdentifier::build(root, first, children) } } impl fmt::Display for ObjectIdentifier<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let show: String = self.into(); write!(f, "{}", show) } } impl fmt::Debug for ObjectIdentifier<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let show: String = self.into(); write!(f, "{}", show) } } #[repr(transparent)] pub struct ArchivedObjectIdentifier { archived: ArchivedVec, } impl Deref for ArchivedObjectIdentifier { type Target = [u8]; fn deref(&self) -> &Self::Target { self.archived.as_slice() } } impl fmt::Debug for ArchivedObjectIdentifier { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, "{}", &convert_to_string(self.archived.as_slice()) .unwrap_or_else(|e| format!("Invalid OID: {:?}", e)) ) } } impl Archive for ObjectIdentifier<'_> { type Archived = ArchivedObjectIdentifier; type Resolver = VecResolver; unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { let (oid_pos, oid_out) = rkyv::out_field!(out.archived); ArchivedVec::resolve_from_slice(self.nodes.as_ref(), pos + oid_pos, resolver, oid_out); } } impl Archive for &'static ObjectIdentifier<'_> { type Archived = ArchivedObjectIdentifier; type Resolver = VecResolver; unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { let (oid_pos, oid_out) = rkyv::out_field!(out.archived); ArchivedVec::resolve_from_slice(self.nodes.as_ref(), pos + oid_pos, resolver, oid_out); } } impl Serialize for ObjectIdentifier<'_> where [u8]: rkyv::SerializeUnsized, { fn serialize(&self, serializer: &mut S) -> Result { ArchivedVec::serialize_from_slice(self.nodes.as_ref(), serializer) } } fn parse_string_first_node(first_child_node: &str) -> Result { let first_child_node: u8 = first_child_node .parse() .map_err(|_| ObjectIdentifierError::IllegalFirstChildNode)?; if first_child_node > 39 { return Err(ObjectIdentifierError::IllegalFirstChildNode); } Ok(first_child_node) } impl ObjectIdentifier<'static> { fn from_string(value: S) -> Result where S: AsRef, { ObjectIdentifier::from_str(value.as_ref()) } } fn convert_to_string(nodes: &[u8]) -> Result { assert!(nodes.len() > 0); let root = nodes[0] / 40; let mut out = root.to_string(); out.push('.'); let first = nodes[0] % 40; out.extend(first.to_string().chars()); let mut parsing_big_int = false; let mut big_int: Node = 0; for i in 1..nodes.len() { if !parsing_big_int && nodes[i] < 128 { // less than 7 bit of node value out.push('.'); let nr = nodes[i].to_string(); out.extend(nr.chars()); } else { if big_int > 0 { if big_int >= Node::MAX >> 7 { return Err(ObjectIdentifierError::IllegalChildNodeValue); } big_int <<= 7; }; big_int += (nodes[i] & !0x80) as Node; parsing_big_int = nodes[i] & 0x80 != 0; } if big_int > 0 && !parsing_big_int { out.push('.'); out.extend(big_int.to_string().chars()); big_int = 0; } } Ok(out) } impl Into for &ObjectIdentifier<'_> { fn into(self) -> String { convert_to_string(&self.nodes).expect("Valid OID object couldn't be serialized.") } } impl Into for ObjectIdentifier <'_>{ fn into(self) -> String { (&self).into() } } impl<'a> Into<&'a [u8]> for &'a ObjectIdentifier<'_> { fn into(self) -> &'a [u8] { &self.nodes } } impl Into> for ObjectIdentifier<'_> { fn into(self) -> Vec { self.nodes.into() } } impl TryFrom<&str> for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; fn try_from(value: &str) -> Result { ObjectIdentifier::from_string(value) } } impl TryFrom for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; fn try_from(value: String) -> Result { ObjectIdentifier::from_string(value) } } impl<'a> TryFrom<&'a [u8]> for ObjectIdentifier<'a> { type Error = ObjectIdentifierError; fn try_from(nodes: &'a [u8]) -> Result { Self::from_box(Cow::Borrowed(nodes)) } } impl TryFrom> for ObjectIdentifier<'static> { type Error = ObjectIdentifierError; fn try_from(value: Vec) -> Result { Self::from_box(Cow::from(value)) } } mod serde_support { use super::*; use core::fmt; use serde::{de, ser}; struct OidVisitor; impl<'de> de::Visitor<'de> for OidVisitor { type Value = ObjectIdentifier<'de>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a valid buffer representing an OID") } fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result where E: de::Error, { ObjectIdentifier::try_from(v).map_err(move |err| { E::invalid_value( de::Unexpected::Other(match err { ObjectIdentifierError::IllegalRootNode => "illegal root node", ObjectIdentifierError::IllegalFirstChildNode => "illegal first child node", ObjectIdentifierError::IllegalChildNodeValue => "illegal child node value", }), &"a valid buffer representing an OID", ) }) } fn visit_str(self, v: &str) -> Result where E: de::Error, { ObjectIdentifier::try_from(v).map_err(|err| { E::invalid_value( de::Unexpected::Other(match err { ObjectIdentifierError::IllegalRootNode => "illegal root node", ObjectIdentifierError::IllegalFirstChildNode => "illegal first child node", ObjectIdentifierError::IllegalChildNodeValue => "illegal child node value", }), &"a string representing an OID", ) }) } } impl<'de> de::Deserialize<'de> for ObjectIdentifier<'de> { fn deserialize(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { if deserializer.is_human_readable() { deserializer.deserialize_str(OidVisitor) } else { deserializer.deserialize_bytes(OidVisitor) } } } impl ser::Serialize for ObjectIdentifier<'_> { fn serialize( &self, serializer: S, ) -> Result<::Ok, ::Error> where S: ser::Serializer, { if serializer.is_human_readable() { let encoded: String = self.into(); serializer.serialize_str(&encoded) } else { serializer.serialize_bytes(self.as_bytes()) } } } impl ser::Serialize for ArchivedObjectIdentifier { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { if serializer.is_human_readable() { let encoded: String = convert_to_string(self.deref()).expect("Failed to convert valid OID to String"); serializer.serialize_str(&encoded) } else { serializer.serialize_bytes(self.deref()) } } } } /// Helper macro to declare Object Identifiers at compile-time /// /// Since the DER encoded oids are not very readable we provide a /// procedural macro `oid!`. The macro can be used the following ways: /// /// - `oid!(1.4.42.23)`: Create a const expression for the corresponding `Oid<'static>` /// - `oid!(rel 42.23)`: Create a const expression for the corresponding relative `Oid<'static>` /// - `oid!(raw 1.4.42.23)`/`oid!(raw rel 42.23)`: Obtain the DER encoded form as a byte array. /// /// # Comparing oids /// /// Comparing a parsed oid to a static oid is probably the most common /// thing done with oids in your code. The `oid!` macro can be used in expression positions for /// this purpose. For example /// ``` /// use diflouroborane::oid; /// use diflouroborane::utils::oid::ObjectIdentifier; /// /// # let some_oid: ObjectIdentifier = oid!(1.2.456); /// const SOME_STATIC_OID: ObjectIdentifier = oid!(1.2.456); /// assert_eq!(some_oid, SOME_STATIC_OID) /// ``` /// To get a relative Oid use `oid!(rel 1.2)`. /// /// Because of limitations for procedural macros ([rust issue](https://github.com/rust-lang/rust/issues/54727)) /// and constants used in patterns ([rust issue](https://github.com/rust-lang/rust/issues/31434)) /// the `oid` macro can not directly be used in patterns, also not through constants. /// You can do this, though: /// ``` /// # use diflouroborane::oid; /// # use diflouroborane::utils::oid::ObjectIdentifier; /// # let some_oid: ObjectIdentifier<'static> = oid!(1.2.456); /// const SOME_OID: ObjectIdentifier<'static> = oid!(1.2.456); /// if some_oid == SOME_OID || some_oid == oid!(1.2.456) { /// println!("match"); /// } /// /// // Alternatively, compare the DER encoded form directly: /// const SOME_OID_RAW: &[u8] = &oid!(raw 1.2.456); /// match some_oid.as_bytes() { /// SOME_OID_RAW => println!("match"), /// _ => panic!("no match"), /// } /// ``` /// *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An /// extra check might be necessary. #[macro_export] macro_rules! oid { (raw $( $item:literal ).*) => { ::bffh_impl::encode_oid!( $( $item ).* ) }; (raw $items:expr) => { ::bffh_impl::encode_oid!($items) }; ($($item:literal ).*) => { $crate::utils::oid::ObjectIdentifier::new_unchecked(::std::borrow::Cow::Borrowed( &$crate::oid!(raw $( $item ).*), )) }; } #[cfg(test)] pub(crate) mod tests { use super::*; use std::convert::TryInto; pub(crate) fn gen_random() -> ObjectIdentifier { let amt: u8 = rand::random::() % 10 + 1; let mut children = Vec::new(); for _ in 0..amt { children.push(rand::random()); } ObjectIdentifier::build(ObjectIdentifierRoot::JointIsoItuT, 25, children).unwrap() } #[test] fn encode_binary_root_node_0() { let expected: Vec = vec![0]; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::ItuT, 0x00, vec![]).unwrap(); let actual: Vec = oid.into(); assert_eq!(expected, actual); } #[test] fn encode_binary_root_node_1() { let expected: Vec = vec![40]; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 0x00, vec![]).unwrap(); let actual: Vec = oid.into(); assert_eq!(expected, actual); } #[test] fn encode_binary_root_node_2() { let expected: Vec = vec![80]; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::JointIsoItuT, 0x00, vec![]).unwrap(); let actual: Vec = oid.into(); assert_eq!(expected, actual); } #[test] fn encode_binary_example_1() { let expected: Vec = vec![0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0D, 0x15]; let oid = ObjectIdentifier::build( ObjectIdentifierRoot::ItuT, 0x01, vec![1, 2, 3, 5, 8, 13, 21], ) .unwrap(); let actual: Vec = oid.into(); assert_eq!(expected, actual); } #[test] fn encode_binary_example_2() { let expected: Vec = vec![ 0x77, 0x2A, 0x93, 0x45, 0x83, 0xFF, 0x7F, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x89, 0x53, 0x92, 0x30, ]; let oid = ObjectIdentifier::build( ObjectIdentifierRoot::JointIsoItuT, 39, vec![42, 2501, 65535, 2147483647, 1235, 2352], ) .unwrap(); let actual: Vec = (oid).into(); assert_eq!(expected, actual); } #[test] fn encode_string_root_node_0() { let expected = "0.0"; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::ItuT, 0x00, vec![]).unwrap(); let actual: String = (oid).into(); assert_eq!(expected, actual); } #[test] fn encode_string_root_node_1() { let expected = "1.0"; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 0x00, vec![]).unwrap(); let actual: String = (&oid).into(); assert_eq!(expected, actual); } #[test] fn encode_string_root_node_2() { let expected = "2.0"; let oid = ObjectIdentifier::build(ObjectIdentifierRoot::JointIsoItuT, 0x00, vec![]).unwrap(); let actual: String = (&oid).into(); assert_eq!(expected, actual); } #[test] fn encode_string_example_1() { let expected = "0.1.1.2.3.5.8.13.21"; let oid = ObjectIdentifier::build( ObjectIdentifierRoot::ItuT, 0x01, vec![1, 2, 3, 5, 8, 13, 21], ) .unwrap(); let actual: String = (&oid).into(); assert_eq!(expected, actual); } #[test] fn encode_string_example_2() { let expected = "2.39.42.2501.65535.2147483647.1235.2352"; let oid = ObjectIdentifier::build( ObjectIdentifierRoot::JointIsoItuT, 39, vec![42, 2501, 65535, 2147483647, 1235, 2352], ) .unwrap(); let actual: String = (&oid).into(); assert_eq!(expected, actual); } #[test] fn parse_binary_root_node_0() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::ItuT, 0x00, vec![]); let actual = vec![0x00].try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_root_node_1() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 0x00, vec![]); let actual = vec![40].try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_root_node_2() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::JointIsoItuT, 0x00, vec![]); let actual = vec![80].try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_example_1() { let expected = ObjectIdentifier::build( ObjectIdentifierRoot::ItuT, 0x01, vec![1, 2, 3, 5, 8, 13, 21], ); let actual = vec![0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0D, 0x15].try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_example_2() { let expected = ObjectIdentifier::build( ObjectIdentifierRoot::JointIsoItuT, 39, vec![42, 2501, 65535, 2147483647, 1235, 2352], ); let actual = vec![ 0x77, 0x2A, 0x93, 0x45, 0x83, 0xFF, 0x7F, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x89, 0x53, 0x92, 0x30, ] .try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_root_node_0() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::ItuT, 0x00, vec![]); let actual = "0.0".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_root_node_1() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 0x00, vec![]); let actual = "1.0".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_root_node_2() { let expected = ObjectIdentifier::build(ObjectIdentifierRoot::JointIsoItuT, 0x00, vec![]); let actual = "2.0".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_example_1() { let expected = ObjectIdentifier::build( ObjectIdentifierRoot::ItuT, 0x01, vec![1, 2, 3, 5, 8, 13, 21], ); let actual = "0.1.1.2.3.5.8.13.21".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_example_2() { let expected = ObjectIdentifier::build( ObjectIdentifierRoot::JointIsoItuT, 39, vec![42, 2501, 65535, 2147483647, 1235, 2352], ); let actual = "2.39.42.2501.65535.2147483647.1235.2352".try_into(); assert_eq!(expected, actual); } #[test] fn illegal_oid_root() { let expected = Err(ObjectIdentifierError::IllegalRootNode); for i in 3..core::u8::MAX { let actual = ObjectIdentifierRoot::try_from(i); assert_eq!(expected, actual); } } #[test] fn illegal_first_node_too_large() { let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); for i in 40..core::u8::MAX { let string_val = format!("{}.2.3.4", i); let mut nodes_iter = string_val.split("."); let actual = parse_string_first_node(nodes_iter.next().unwrap()); assert_eq!(expected, actual); } } #[test] fn illegal_first_node_empty() { let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); let string_val = String::new(); let mut nodes_iter = string_val.split("."); let actual = parse_string_first_node(nodes_iter.next().unwrap()); assert_eq!(expected, actual); } #[test] fn illegal_first_node_large() { let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); let string_val = String::from("40"); let mut nodes_iter = string_val.split("."); let actual = parse_string_first_node(nodes_iter.next().unwrap()); assert_eq!(expected, actual); } #[test] fn parse_string_crap() { let expected: Result = Err(ObjectIdentifierError::IllegalRootNode); let actual = "wtf".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_empty() { let expected: Result = Err(ObjectIdentifierError::IllegalRootNode); let actual = String::new().try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_empty() { let expected: Result = Err(ObjectIdentifierError::IllegalRootNode); let actual = vec![].try_into(); assert_eq!(expected, actual); } #[test] fn parse_binary_example_over_u128() { let expected: Result = Err(ObjectIdentifierError::IllegalChildNodeValue); let actual = vec![ 0x00, 0x89, 0x97, 0xBF, 0xA3, 0xB8, 0xE8, 0xB3, 0xE6, 0xFB, 0xF2, 0xEA, 0xC3, 0xCA, 0xF2, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, ] .try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_root_node_3plus() { for i in 3..=core::u8::MAX { let expected: Result = Err(ObjectIdentifierError::IllegalRootNode); let actual = format!("{}", i).try_into(); assert_eq!(expected, actual); } } #[test] fn parse_string_example_over_u128() { let expected: Result = Err(ObjectIdentifierError::IllegalChildNodeValue); let actual = "1.1.349239782398732987223423423423423423423423423423434982342342342342342342324523453452345234523452345234523452345234537234987234".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_example_first_node_over_39() { let expected: Result = Err(ObjectIdentifierError::IllegalFirstChildNode); let actual = "1.40.1.2.3".try_into(); assert_eq!(expected, actual); } #[test] fn parse_string_large_children_ok() { let expected = ObjectIdentifier::build( ObjectIdentifierRoot::JointIsoItuT, 25, vec![ 190754093376743485973207716749546715206, 255822649272987943607843257596365752308, 15843412533224453995377625663329542022, 6457999595881951503805148772927347934, 19545192863105095042881850060069531734, 195548685662657784196186957311035194990, 233020488258340943072303499291936117654, 193307160423854019916786016773068715190, ], ) .unwrap(); let actual = "2.25.190754093376743485973207716749546715206.\ 255822649272987943607843257596365752308.\ 15843412533224453995377625663329542022.\ 6457999595881951503805148772927347934.\ 19545192863105095042881850060069531734.\ 195548685662657784196186957311035194990.\ 233020488258340943072303499291936117654.\ 193307160423854019916786016773068715190" .try_into() .unwrap(); assert_eq!(expected, actual); } #[test] fn encode_to_string() { let expected = String::from("1.2.3.4"); let actual: String = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 2, vec![3, 4]) .unwrap() .into(); assert_eq!(expected, actual); } #[test] fn encode_to_bytes() { let expected = vec![0x2A, 0x03, 0x04]; let actual: Vec = ObjectIdentifier::build(ObjectIdentifierRoot::Iso, 2, vec![3, 4]) .unwrap() .into(); assert_eq!(expected, actual); } }