use crate::{DynTagged, Error, Result, Tag}; #[cfg(feature = "std")] use crate::{SerializeResult, ToDer}; use core::ops; /// BER Object Length #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Length { /// Definite form (X.690 8.1.3.3) Definite(usize), /// Indefinite form (X.690 8.1.3.6) Indefinite, } impl Length { /// Return true if length is definite and equal to 0 #[inline] pub fn is_null(&self) -> bool { *self == Length::Definite(0) } /// Get length of primitive object #[inline] pub fn definite(&self) -> Result { match self { Length::Definite(sz) => Ok(*sz), Length::Indefinite => Err(Error::IndefiniteLengthUnexpected), } } /// Return true if length is definite #[inline] pub const fn is_definite(&self) -> bool { matches!(self, Length::Definite(_)) } /// Return error if length is not definite #[inline] pub const fn assert_definite(&self) -> Result<()> { match self { Length::Definite(_) => Ok(()), Length::Indefinite => Err(Error::IndefiniteLengthUnexpected), } } } impl From for Length { fn from(l: usize) -> Self { Length::Definite(l) } } impl ops::Add for Length { type Output = Self; fn add(self, rhs: Length) -> Self::Output { match self { Length::Indefinite => self, Length::Definite(lhs) => match rhs { Length::Indefinite => rhs, Length::Definite(rhs) => Length::Definite(lhs + rhs), }, } } } impl ops::Add for Length { type Output = Self; fn add(self, rhs: usize) -> Self::Output { match self { Length::Definite(lhs) => Length::Definite(lhs + rhs), Length::Indefinite => self, } } } impl ops::AddAssign for Length { fn add_assign(&mut self, rhs: usize) { match self { Length::Definite(ref mut lhs) => *lhs += rhs, Length::Indefinite => (), } } } impl DynTagged for Length { fn tag(&self) -> Tag { Tag(0) } } #[cfg(feature = "std")] impl ToDer for Length { fn to_der_len(&self) -> Result { match self { Length::Indefinite => Ok(1), Length::Definite(l) => match l { 0..=0x7f => Ok(1), 0x80..=0xff => Ok(2), 0x100..=0xffff => Ok(3), 0x1_0000..=0xffff_ffff => Ok(4), _ => Err(Error::InvalidLength), }, } } fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult { match *self { Length::Indefinite => { let sz = writer.write(&[0b1000_0000])?; Ok(sz) } Length::Definite(l) => { if l <= 127 { // Short form let sz = writer.write(&[l as u8])?; Ok(sz) } else { // Long form let b = l.to_be_bytes(); // skip leading zeroes // we do not have to test for length, l cannot be 0 let mut idx = 0; while b[idx] == 0 { idx += 1; } let b = &b[idx..]; // first byte: 0x80 + length of length let b0 = 0x80 | (b.len() as u8); let sz = writer.write(&[b0])?; let sz = sz + writer.write(b)?; Ok(sz) } } } } fn write_der_content(&self, _writer: &mut dyn std::io::Write) -> SerializeResult { Ok(0) } } #[cfg(test)] mod tests { use crate::*; /// Generic and coverage tests #[test] fn methods_length() { let l = Length::from(2); assert_eq!(l.definite(), Ok(2)); assert!(l.assert_definite().is_ok()); let l = Length::Indefinite; assert!(l.definite().is_err()); assert!(l.assert_definite().is_err()); let l = Length::from(2); assert_eq!(l + 2, Length::from(4)); assert_eq!(l + Length::Indefinite, Length::Indefinite); let l = Length::Indefinite; assert_eq!(l + 2, Length::Indefinite); let l = Length::from(2); assert_eq!(l + Length::from(2), Length::from(4)); let l = Length::Indefinite; assert_eq!(l + Length::from(2), Length::Indefinite); let mut l = Length::from(2); l += 2; assert_eq!(l.definite(), Ok(4)); let mut l = Length::Indefinite; l += 2; assert_eq!(l, Length::Indefinite); } }