use crate::{DynTagged, Error, Result, Tag};
#[cfg(feature = "std")]
use crate::{SerializeResult, ToDer};
use core::ops;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Length {
Definite(usize),
Indefinite,
}
impl Length {
#[inline]
pub fn is_null(&self) -> bool {
*self == Length::Definite(0)
}
#[inline]
pub fn definite(&self) -> Result<usize> {
match self {
Length::Definite(sz) => Ok(*sz),
Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
}
}
#[inline]
pub const fn is_definite(&self) -> bool {
matches!(self, Length::Definite(_))
}
#[inline]
pub const fn assert_definite(&self) -> Result<()> {
match self {
Length::Definite(_) => Ok(()),
Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
}
}
}
impl From<usize> for Length {
fn from(l: usize) -> Self {
Length::Definite(l)
}
}
impl ops::Add<Length> 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<usize> 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<usize> 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<usize> {
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<usize> {
match *self {
Length::Indefinite => {
let sz = writer.write(&[0b1000_0000])?;
Ok(sz)
}
Length::Definite(l) => {
if l <= 127 {
let sz = writer.write(&[l as u8])?;
Ok(sz)
} else {
let b = l.to_be_bytes();
let mut idx = 0;
while b[idx] == 0 {
idx += 1;
}
let b = &b[idx..];
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<usize> {
Ok(0)
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[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);
}
}