1use bitfield_struct::bitfield;
4use num_enum::TryFromPrimitive;
5
6use crate::id::tag::IntoTagType;
7
8#[bitfield(u8, debug = false)]
10pub struct TagTypeSize {
11 #[bits(2)]
13 pub encoded_size: SizeBits,
14 #[bits(2)]
16 pub ty: TypeBits,
17 #[bits(4)]
19 pub tag: u8,
20}
21
22impl TagTypeSize {
23 pub fn from_tag<T: IntoTagType>(tag: T, data_len: usize) -> Self {
25 let size = SizeBits::from_size(data_len);
26 tag.encode_tag().with_encoded_size(size)
27 }
28
29 pub fn size(self) -> Size {
31 if self.ty() == TypeBits::Reserved
32 && self.tag() == 0xF
33 && self.encoded_size() == SizeBits::Two
34 {
35 Size::Long
37 } else {
38 Size::Short(self.encoded_size().size_bytes())
39 }
40 }
41}
42
43pub fn encode_unsigned(data: &[u8]) -> &[u8] {
47 if data.is_empty() {
48 return data;
49 }
50 assert!(data.len() <= 4 && data.len() != 3);
51 let count_zero = data.iter().rev().take_while(|&&b| b == 0).count();
52 let mut truncated_len = data.len() - count_zero;
53 if truncated_len == 0 {
55 truncated_len = 1;
56 }
57 if truncated_len == 3 {
59 truncated_len = 4;
60 }
61 &data[..truncated_len]
62}
63
64pub fn encode_signed(data: &[u8]) -> &[u8] {
75 fn can_drop(&&[lsb, msb]: &&[u8; 2]) -> bool {
77 (msb == 0 && ((lsb & 0x80) == 0)) ||
79 (msb == 0xFF) && ((lsb & 0x80) != 0)
81 }
82
83 if data.is_empty() {
84 return data;
85 }
86
87 let count_zero = data.array_windows::<2>().rev().take_while(can_drop).count();
88 let mut truncated_len = data.len() - count_zero;
89 if truncated_len == 3 {
91 truncated_len = 4;
92 }
93 &data[..truncated_len]
94}
95
96pub enum Size {
98 Short(usize),
100 Long,
102}
103
104#[expect(missing_docs)]
106#[derive(Clone, Copy, Debug, PartialEq, Eq)]
107#[repr(u8)]
108pub enum SizeBits {
109 Zero = 0,
110 One = 1,
111 Two = 2,
112 Four = 3,
113}
114
115impl SizeBits {
116 pub const fn into_bits(self) -> u8 {
118 self as _
119 }
120
121 pub const fn from_bits(value: u8) -> Self {
129 match value {
130 0 => Self::Zero,
131 1 => Self::One,
132 2 => Self::Two,
133 3 => Self::Four,
134 _ => panic!("SizeBits value out of range"),
135 }
136 }
137
138 pub fn size_bytes(self) -> usize {
142 match self {
143 SizeBits::Zero => 0,
144 SizeBits::One => 1,
145 SizeBits::Two => 2,
146 SizeBits::Four => 4,
147 }
148 }
149
150 pub fn from_size(size: usize) -> Self {
152 match size {
153 0 => SizeBits::Zero,
154 1 => SizeBits::One,
155 2 => SizeBits::Two,
156 4 => SizeBits::Four,
157 n => panic!("improper short item size ({n})"),
158 }
159 }
160}
161
162#[expect(missing_docs)]
164#[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)]
165#[repr(u8)]
166pub enum TypeBits {
167 Main = 0,
168 Global = 1,
169 Local = 2,
170 Reserved = 3,
171}
172
173impl TypeBits {
174 pub const fn into_bits(self) -> u8 {
176 self as _
177 }
178
179 pub const fn from_bits(value: u8) -> Self {
188 match value {
189 0 => Self::Main,
190 1 => Self::Global,
191 2 => Self::Local,
192 3 => Self::Reserved,
193 _ => panic!("TypeBits value out of range"),
194 }
195 }
196}
197
198#[cfg(feature = "std")]
199mod std_impls {
200 use super::*;
201 use std::fmt::{self, Debug};
202
203 impl Debug for TagTypeSize {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 f.debug_struct("TagTypeSize")
206 .field("raw", &format_args!("{:#04x}", self.into_bits()))
207 .field("size", &self.encoded_size().size_bytes())
208 .field("type", &self.ty())
209 .field("tag", &format_args!("{:#x}", self.tag()))
210 .finish()
211 }
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_unsigned_encoding() {
221 let unsigned_values = [
224 (0u32, &[0x00][..]),
225 (0x7F, &[0x7F]),
226 (0x80, &[0x80]),
227 (0xFF, &[0xFF]),
228 (0x100, &[0x00, 0x01]),
229 (0xFFFF, &[0xFF, 0xFF]),
230 (0x123456, &[0x56, 0x34, 0x12, 0x00]),
231 ];
232 for (value, expected) in unsigned_values {
233 assert_eq!(expected, encode_unsigned(&value.to_le_bytes()))
234 }
235 }
236
237 #[test]
238 fn test_signed_encoding() {
239 let signed_values = [
243 (0i32, &[0x00][..]),
244 (1i32, &[0x01]),
245 (0x7F, &[0x7F]),
246 (0x80, &[0x80, 0x00]),
247 (0xFF, &[0xFF, 0x00]),
248 (0x100, &[0x00, 0x01]),
249 (0xFFFF, &[0xFF, 0xFF, 0x00, 0x00]),
250 (0x123456, &[0x56, 0x34, 0x12, 0x00]),
251 (-1, &[0xFF]),
252 (-128, &[0x80]),
253 (-129, &[0x7F, 0xFF]),
254 (-32768, &[0x00, 0x80]),
255 (-32769, &[0xFF, 0x7F, 0xFF, 0xFF]),
256 (-2147483648, &[0x00, 0x00, 0x00, 0x80]),
257 ];
258 for (value, expected) in signed_values {
259 let bytes = value.to_le_bytes();
260 let encoded = encode_signed(&bytes);
261 assert_eq!(
262 expected, encoded,
263 "expected {:X?}, got {:X?}",
264 expected, encoded
265 )
266 }
267 }
268}