1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
7)]
8#![allow(clippy::len_without_is_empty)]
9#![deny(unsafe_code)]
10#![warn(
11 clippy::arithmetic_side_effects,
12 clippy::mod_module_files,
13 clippy::panic,
14 clippy::panic_in_result_fn,
15 clippy::unwrap_used,
16 missing_docs,
17 rust_2018_idioms,
18 unused_lifetimes,
19 unused_qualifications
20)]
21
22#[macro_use]
23mod checked;
24
25mod arcs;
26mod buffer;
27mod encoder;
28mod error;
29mod parser;
30mod traits;
31
32#[cfg(feature = "db")]
33pub mod db;
34
35pub use crate::{
36 arcs::{Arc, Arcs},
37 buffer::Buffer,
38 error::{Error, Result},
39 traits::{AssociatedOid, DynAssociatedOid},
40};
41
42use crate::encoder::Encoder;
43use core::{borrow::Borrow, fmt, ops::Deref, str::FromStr};
44
45const DEFAULT_MAX_SIZE: usize = 39;
49
50#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
66pub struct ObjectIdentifier<const MAX_SIZE: usize = DEFAULT_MAX_SIZE> {
67 ber: Buffer<MAX_SIZE>,
69}
70
71impl ObjectIdentifier {
72 pub const MAX_SIZE: usize = DEFAULT_MAX_SIZE;
74
75 pub const fn new_unwrap(s: &str) -> Self {
94 match Self::new(s) {
95 Ok(oid) => oid,
96 Err(err) => err.panic(),
97 }
98 }
99
100 pub const fn new(s: &str) -> Result<Self> {
102 match parser::Parser::parse(s) {
104 Ok(parser) => parser.finish(),
105 Err(err) => Err(err),
106 }
107 }
108
109 pub fn from_arcs(arcs: impl IntoIterator<Item = Arc>) -> Result<Self> {
111 let mut encoder = Encoder::new();
112
113 for arc in arcs {
114 encoder = encoder.arc(arc)?;
115 }
116
117 encoder.finish()
118 }
119
120 pub fn from_bytes(ber_bytes: &[u8]) -> Result<Self> {
122 Self::from_bytes_sized(ber_bytes)
123 }
124}
125
126impl<const MAX_SIZE: usize> ObjectIdentifier<MAX_SIZE> {
127 pub fn from_bytes_sized(ber_bytes: &[u8]) -> Result<Self> {
131 ObjectIdentifierRef::from_bytes(ber_bytes)?.try_into()
132 }
133
134 pub const fn as_bytes(&self) -> &[u8] {
139 self.ber.as_bytes()
140 }
141
142 pub const fn as_oid_ref(&self) -> &ObjectIdentifierRef {
144 ObjectIdentifierRef::from_bytes_unchecked(self.as_bytes())
145 }
146
147 pub fn parent(&self) -> Option<Self> {
149 let num_arcs = self.len().checked_sub(1)?;
150 let mut encoder = Encoder::new();
151
152 for arc in self.arcs().take(num_arcs) {
153 encoder = encoder.arc(arc).ok()?;
154 }
155
156 encoder.finish().ok()
157 }
158
159 pub const fn push_arc(self, arc: Arc) -> Result<Self> {
161 match Encoder::extend(self).arc(arc) {
163 Ok(encoder) => encoder.finish(),
164 Err(err) => Err(err),
165 }
166 }
167
168 pub const fn starts_with<const SIZE: usize>(&self, other: ObjectIdentifier<SIZE>) -> bool {
170 let len = other.as_bytes().len();
171
172 if self.as_bytes().len() < len {
173 return false;
174 }
175
176 let mut i = 0;
177 while i < len {
178 if self.as_bytes()[i] != other.as_bytes()[i] {
179 return false;
180 }
181
182 match i.checked_add(1) {
183 Some(succ) => i = succ,
184 None => return false,
185 }
186 }
187
188 true
189 }
190}
191
192impl<const MAX_SIZE: usize> AsRef<[u8]> for ObjectIdentifier<MAX_SIZE> {
193 fn as_ref(&self) -> &[u8] {
194 self.as_bytes()
195 }
196}
197
198impl<const MAX_SIZE: usize> AsRef<ObjectIdentifierRef> for ObjectIdentifier<MAX_SIZE> {
199 fn as_ref(&self) -> &ObjectIdentifierRef {
200 self.as_oid_ref()
201 }
202}
203
204impl<const MAX_SIZE: usize> Borrow<ObjectIdentifierRef> for ObjectIdentifier<MAX_SIZE> {
205 fn borrow(&self) -> &ObjectIdentifierRef {
206 self.as_oid_ref()
207 }
208}
209
210impl<const MAX_SIZE: usize> Deref for ObjectIdentifier<MAX_SIZE> {
211 type Target = ObjectIdentifierRef;
212
213 fn deref(&self) -> &ObjectIdentifierRef {
214 self.as_oid_ref()
215 }
216}
217
218impl FromStr for ObjectIdentifier {
219 type Err = Error;
220
221 fn from_str(string: &str) -> Result<Self> {
222 Self::new(string)
223 }
224}
225
226impl TryFrom<&[u8]> for ObjectIdentifier {
227 type Error = Error;
228
229 fn try_from(ber_bytes: &[u8]) -> Result<Self> {
230 Self::from_bytes(ber_bytes)
231 }
232}
233
234impl<const MAX_SIZE: usize> TryFrom<&ObjectIdentifierRef> for ObjectIdentifier<MAX_SIZE> {
235 type Error = Error;
236
237 fn try_from(oid_ref: &ObjectIdentifierRef) -> Result<Self> {
238 let len = oid_ref.as_bytes().len();
239
240 if len > MAX_SIZE {
241 return Err(Error::Length);
242 }
243
244 let mut bytes = [0u8; MAX_SIZE];
245 bytes[..len].copy_from_slice(oid_ref.as_bytes());
246
247 let ber = Buffer {
248 bytes,
249 length: len as u8,
250 };
251
252 Ok(Self { ber })
253 }
254}
255
256impl<const MAX_SIZE: usize> fmt::Debug for ObjectIdentifier<MAX_SIZE> {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 write!(f, "ObjectIdentifier({self})")
259 }
260}
261
262impl<const MAX_SIZE: usize> fmt::Display for ObjectIdentifier<MAX_SIZE> {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 write!(f, "{}", self.as_oid_ref())
265 }
266}
267
268#[cfg(feature = "arbitrary")]
271impl<'a> arbitrary::Arbitrary<'a> for ObjectIdentifier {
272 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
273 let first = u.int_in_range(0..=arcs::ARC_MAX_FIRST)?;
274 let second = u.int_in_range(0..=arcs::ARC_MAX_SECOND)?;
275 let third = u.arbitrary()?;
276
277 let mut oid = Self::from_arcs([first, second, third])
278 .map_err(|_| arbitrary::Error::IncorrectFormat)?;
279
280 for arc in u.arbitrary_iter()? {
281 oid = oid
282 .push_arc(arc?)
283 .map_err(|_| arbitrary::Error::IncorrectFormat)?;
284 }
285
286 Ok(oid)
287 }
288
289 fn size_hint(depth: usize) -> (usize, Option<usize>) {
290 (Arc::size_hint(depth).0.saturating_mul(3), None)
291 }
292}
293
294#[derive(Eq, Hash, PartialEq, PartialOrd, Ord)]
296#[repr(transparent)]
297pub struct ObjectIdentifierRef {
298 ber: [u8],
300}
301
302impl ObjectIdentifierRef {
303 pub fn from_bytes(ber: &[u8]) -> Result<&Self> {
307 let mut arcs = Arcs::new(ber);
309 while arcs.try_next()?.is_some() {}
310 Ok(Self::from_bytes_unchecked(ber))
311 }
312
313 pub(crate) const fn from_bytes_unchecked(ber: &[u8]) -> &Self {
316 debug_assert!(!ber.is_empty());
317
318 #[allow(unsafe_code)]
320 unsafe {
321 &*(ber as *const [u8] as *const ObjectIdentifierRef)
322 }
323 }
324
325 pub const fn as_bytes(&self) -> &[u8] {
330 &self.ber
331 }
332
333 pub fn arc(&self, index: usize) -> Option<Arc> {
335 self.arcs().nth(index)
336 }
337
338 pub fn arcs(&self) -> Arcs<'_> {
342 Arcs::new(self.ber.as_ref())
343 }
344
345 pub fn len(&self) -> usize {
347 self.arcs().count()
348 }
349}
350
351impl AsRef<[u8]> for ObjectIdentifierRef {
352 fn as_ref(&self) -> &[u8] {
353 self.as_bytes()
354 }
355}
356
357impl<'a, const MAX_SIZE: usize> From<&'a ObjectIdentifier<MAX_SIZE>> for &'a ObjectIdentifierRef {
358 fn from(oid: &'a ObjectIdentifier<MAX_SIZE>) -> &'a ObjectIdentifierRef {
359 oid.as_oid_ref()
360 }
361}
362
363impl<'a> TryFrom<&'a [u8]> for &'a ObjectIdentifierRef {
364 type Error = Error;
365
366 fn try_from(ber_bytes: &'a [u8]) -> Result<Self> {
367 ObjectIdentifierRef::from_bytes(ber_bytes)
368 }
369}
370
371impl fmt::Debug for ObjectIdentifierRef {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 write!(f, "ObjectIdentifierRef({self})")
374 }
375}
376
377impl fmt::Display for ObjectIdentifierRef {
378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379 let len = self.arcs().count();
380
381 for (i, arc) in self.arcs().enumerate() {
382 write!(f, "{arc}")?;
383
384 if let Some(j) = i.checked_add(1) {
385 if j < len {
386 write!(f, ".")?;
387 }
388 }
389 }
390
391 Ok(())
392 }
393}
394
395impl<const MAX_SIZE: usize> PartialEq<ObjectIdentifier<MAX_SIZE>> for ObjectIdentifierRef {
396 fn eq(&self, other: &ObjectIdentifier<MAX_SIZE>) -> bool {
397 self.as_bytes().eq(other.as_bytes())
398 }
399}