basn1/intenc.rs
1//! Integer encoding used in ASN.1
2//!
3//! * 7bit highest-continuation encoding
4//! * 8bit variable encoding encoding slice
5
6/// A simple encoded variable size integer where limbs
7/// are 7 bits, and big endian, and continuation of
8/// the encoding is indicated by having the highest bit set
9#[derive(Debug, PartialEq, Eq, Hash)]
10pub(crate) struct IntegerContBit7([u8]);
11
12macro_rules! to_primitive7 {
13 ($type: ident, $name: ident) => {
14 /// Try to convert to the primitive
15 ///
16 /// If there's an overflown then nothing is returned
17 pub fn $name(&self) -> Option<$type> {
18 // this function assume that the data has been checked properly
19 // so that the first byte is not a long zero,
20 // and that the continuation bit are correctly set
21 // for each byte limb.
22 let mut acc = (self.0[0] & 0b0111_1111) as $type;
23 for c in &self.0[1..] {
24 acc = acc
25 .checked_shl(7)?
26 .checked_add((c & 0b0111_1111) as $type)?
27 }
28 Some(acc)
29 }
30 };
31}
32
33impl IntegerContBit7 {
34 /// transform a raw slice into a IntegerContBit7 slice,
35 /// no verification is done by this call
36 /// one should use parse_from_slice for safe parsing+verification
37 pub(crate) fn unverified_from_slice(slice: &[u8]) -> &Self {
38 cast_slice_u8_to_typed_slice!(slice, Self)
39 }
40
41 /// Try to parse from a slice
42 pub fn parse_from_slice(slice: &[u8]) -> Result<(&Self, usize), ()> {
43 if slice.is_empty() {
44 return Err(());
45 }
46 if slice[0] == 0b1000_0000 {
47 return Err(());
48 }
49 let mut i = 0;
50 while (slice[i] & 0b1000_0000) != 0 {
51 i += 1;
52 if i == slice.len() {
53 return Err(());
54 }
55 }
56 let r = Self::unverified_from_slice(&slice[0..1 + i]);
57 Ok((r, 1 + i))
58 }
59
60 to_primitive7!(u128, to_u128);
61 to_primitive7!(u64, to_u64);
62 to_primitive7!(u32, to_u32);
63 to_primitive7!(u16, to_u16);
64 to_primitive7!(u8, to_u8);
65
66 /*
67 pub fn as_be() -> BeIntegerBytes<'a> {
68 todo!()
69 }
70
71 pub fn as_le() -> LeIntegerBytes<'a> {
72 todo!()
73 }
74 */
75}
76
77slice_reexport_asref!(IntegerContBit7);
78
79/// An encoded integer where each limbs is 8bits and in big endian
80#[derive(Debug, PartialEq, Eq, Hash)]
81pub(crate) struct Integer8Bit([u8]);
82
83macro_rules! to_primitive8 {
84 ($type: ident, $name: ident) => {
85 /// Try to convert to the primitive
86 ///
87 /// If there's an overflown then nothing is returned
88 pub fn $name(&self) -> Option<$type> {
89 // this function assume that the data has been checked properly
90 // so that the first byte is not a long zero,
91 // and that the continuation bit are correctly set
92 // for each byte limb.
93 let mut acc = self.0[0] as $type;
94 for c in &self.0[1..] {
95 acc = acc.checked_shl(8)?.checked_add(*c as $type)?
96 }
97 Some(acc)
98 }
99 };
100}
101
102impl Integer8Bit {
103 /// transform a raw slice into a Integer8Bit slice,
104 /// no verification is done by this call
105 pub(crate) fn unverified_from_slice(slice: &[u8]) -> &Self {
106 cast_slice_u8_to_typed_slice!(slice, Self)
107 }
108
109 /// Try to parse from a slice
110 pub fn from_slice(slice: &[u8]) -> Result<&Self, ()> {
111 if slice.is_empty() || slice[0] == 0 {
112 return Err(());
113 }
114 Ok(Self::unverified_from_slice(slice))
115 }
116
117 to_primitive8!(u128, to_u128);
118 to_primitive8!(u64, to_u64);
119 to_primitive8!(u32, to_u32);
120 to_primitive8!(u16, to_u16);
121 to_primitive8!(u8, to_u8);
122
123 /*
124 pub fn as_be() -> BeIntegerBytes<'a> {}
125
126 pub fn as_le() -> LeIntegerBytes<'a> {
127 todo!()
128 }
129 */
130}
131
132slice_reexport_asref!(Integer8Bit);