1use crate::{DynTagged, Error, Result, Tag};
2#[cfg(feature = "std")]
3use crate::{SerializeResult, ToDer};
4use core::ops;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8pub enum Length {
9 Definite(usize),
11 Indefinite,
13}
14
15impl Length {
16 #[inline]
18 pub fn is_null(&self) -> bool {
19 *self == Length::Definite(0)
20 }
21
22 #[inline]
24 pub fn definite(&self) -> Result<usize> {
25 match self {
26 Length::Definite(sz) => Ok(*sz),
27 Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
28 }
29 }
30
31 #[inline]
33 pub const fn is_definite(&self) -> bool {
34 matches!(self, Length::Definite(_))
35 }
36
37 #[inline]
39 pub const fn assert_definite(&self) -> Result<()> {
40 match self {
41 Length::Definite(_) => Ok(()),
42 Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
43 }
44 }
45}
46
47impl From<usize> for Length {
48 fn from(l: usize) -> Self {
49 Length::Definite(l)
50 }
51}
52
53impl ops::Add<Length> for Length {
54 type Output = Self;
55
56 fn add(self, rhs: Length) -> Self::Output {
57 match self {
58 Length::Indefinite => self,
59 Length::Definite(lhs) => match rhs {
60 Length::Indefinite => rhs,
61 Length::Definite(rhs) => Length::Definite(lhs + rhs),
62 },
63 }
64 }
65}
66
67impl ops::Add<usize> for Length {
68 type Output = Self;
69
70 fn add(self, rhs: usize) -> Self::Output {
71 match self {
72 Length::Definite(lhs) => Length::Definite(lhs + rhs),
73 Length::Indefinite => self,
74 }
75 }
76}
77
78impl ops::AddAssign<usize> for Length {
79 fn add_assign(&mut self, rhs: usize) {
80 match self {
81 Length::Definite(ref mut lhs) => *lhs += rhs,
82 Length::Indefinite => (),
83 }
84 }
85}
86
87impl DynTagged for Length {
88 fn tag(&self) -> Tag {
89 Tag(0)
90 }
91}
92
93#[cfg(feature = "std")]
94impl ToDer for Length {
95 fn to_der_len(&self) -> Result<usize> {
96 match self {
97 Length::Indefinite => Ok(1),
98 Length::Definite(l) => match l {
99 0..=0x7f => Ok(1),
100 0x80..=0xff => Ok(2),
101 0x100..=0xffff => Ok(3),
102 0x1_0000..=0xffff_ffff => Ok(4),
103 _ => Err(Error::InvalidLength),
104 },
105 }
106 }
107
108 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
109 match *self {
110 Length::Indefinite => {
111 let sz = writer.write(&[0b1000_0000])?;
112 Ok(sz)
113 }
114 Length::Definite(l) => {
115 if l <= 127 {
116 let sz = writer.write(&[l as u8])?;
118 Ok(sz)
119 } else {
120 let b = l.to_be_bytes();
122 let mut idx = 0;
125 while b[idx] == 0 {
126 idx += 1;
127 }
128 let b = &b[idx..];
129 let b0 = 0x80 | (b.len() as u8);
131 let sz = writer.write(&[b0])?;
132 let sz = sz + writer.write(b)?;
133 Ok(sz)
134 }
135 }
136 }
137 }
138
139 fn write_der_content(&self, _writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
140 Ok(0)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::*;
147
148 #[test]
150 fn methods_length() {
151 let l = Length::from(2);
152 assert_eq!(l.definite(), Ok(2));
153 assert!(l.assert_definite().is_ok());
154
155 let l = Length::Indefinite;
156 assert!(l.definite().is_err());
157 assert!(l.assert_definite().is_err());
158
159 let l = Length::from(2);
160 assert_eq!(l + 2, Length::from(4));
161 assert_eq!(l + Length::Indefinite, Length::Indefinite);
162
163 let l = Length::Indefinite;
164 assert_eq!(l + 2, Length::Indefinite);
165
166 let l = Length::from(2);
167 assert_eq!(l + Length::from(2), Length::from(4));
168
169 let l = Length::Indefinite;
170 assert_eq!(l + Length::from(2), Length::Indefinite);
171
172 let mut l = Length::from(2);
173 l += 2;
174 assert_eq!(l.definite(), Ok(4));
175
176 let mut l = Length::Indefinite;
177 l += 2;
178 assert_eq!(l, Length::Indefinite);
179 }
180}