Skip to main content

oxirush_aper/
bits.rs

1//! Bit strings: a short one is a number with a length, a long one is octets with a
2//! length.
3
4use alloc::format;
5use alloc::vec::Vec;
6use core::fmt;
7
8use crate::octets::write_hex;
9use crate::{Error, ErrorKind, Octets};
10
11/// A BIT STRING of 64 bits at most: a number with a length.
12///
13/// The first bit of the string is the most significant bit of the number, as the
14/// specifications read an identifier that is a bit string: an AMF Set ID of ten bits is
15/// the number of the set.
16///
17/// ```
18/// use oxirush_aper::Bits;
19///
20/// // An AMF Set ID: ten bits
21/// let set = Bits::new(0x155, 10)?;
22/// assert_eq!(set.value(), 0x155);
23/// assert_eq!(set.len(), 10);
24///
25/// // A number that does not fit in its bits is refused
26/// assert!(Bits::new(1024, 10).is_err());
27///
28/// // Of the width of a number, without a check
29/// assert_eq!(Bits::from(0xE000u16), Bits::new(0xE000, 16)?);
30///
31/// // As octets, the last one padded with zero bits
32/// assert_eq!(set.to_vec(), [0x55, 0x40]);
33/// assert_eq!(Bits::from_octets(&[0x55, 0x40], 10)?, set);
34/// # Ok::<(), oxirush_aper::Error>(())
35/// ```
36#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
37pub struct Bits {
38    value: u64,
39    length: u8,
40}
41
42impl Bits {
43    /// No bit.
44    pub const EMPTY: Self = Self {
45        value: 0,
46        length: 0,
47    };
48
49    /// The bit string of `length` bits that is the number `value`.
50    ///
51    /// # Errors
52    ///
53    /// An error of the kind `Argument` for more than 64 bits, and for a number that
54    /// does not fit in `length` bits.
55    pub fn new(value: u64, length: usize) -> Result<Self, Error> {
56        if length > 64 {
57            return Err(Error::new(
58                ErrorKind::Argument,
59                format!("a bit string of {length} bits is no number of 64 bits: it is a BitString"),
60            ));
61        }
62        if length < 64 && value >> length != 0 {
63            return Err(Error::new(
64                ErrorKind::Argument,
65                format!("{value} does not fit in {length} bits"),
66            ));
67        }
68        Ok(Self {
69            value,
70            length: length as u8,
71        })
72    }
73
74    /// The bit string that is the `length` least significant bits of `value`: 64 bits
75    /// for a longer one.
76    pub const fn low(value: u64, length: usize) -> Self {
77        match length {
78            0 => Self::EMPTY,
79            1..=63 => Self {
80                value: value & ((1 << length) - 1),
81                length: length as u8,
82            },
83            _ => Self { value, length: 64 },
84        }
85    }
86
87    /// The number that the bits are, the first bit the most significant.
88    pub const fn value(&self) -> u64 {
89        self.value
90    }
91
92    /// How many bits the string has.
93    pub const fn len(&self) -> usize {
94        self.length as usize
95    }
96
97    /// Whether the string has no bit.
98    pub const fn is_empty(&self) -> bool {
99        self.length == 0
100    }
101
102    /// The bit at a position, the first one at 0; `None` after the last.
103    pub const fn get(&self, position: usize) -> Option<bool> {
104        if position >= self.length as usize {
105            return None;
106        }
107        Some(self.value >> (self.length as usize - 1 - position) & 1 == 1)
108    }
109
110    /// The bits from the first, in eight octets, with zero bits after the last.
111    pub(crate) const fn leading(&self) -> [u8; 8] {
112        match self.length {
113            0 => [0; 8],
114            length => (self.value << (64 - length)).to_be_bytes(),
115        }
116    }
117
118    /// The octets of the string, the last one padded with zero bits.
119    pub fn to_vec(&self) -> Vec<u8> {
120        self.leading()[..self.len().div_ceil(8)].to_vec()
121    }
122
123    /// The bit string of `length` bits that `octets` hold from their first bit.
124    ///
125    /// # Errors
126    ///
127    /// An error of the kind `Argument` for more than 64 bits, for other octets than
128    /// `length` bits take, and for bits after the last one that are not zero.
129    pub fn from_octets(octets: &[u8], length: usize) -> Result<Self, Error> {
130        check_octets(octets, length)?;
131        if length > 64 {
132            return Self::new(0, length);
133        }
134        let mut leading = [0; 8];
135        leading[..octets.len()].copy_from_slice(octets);
136        let value = match length {
137            0 => 0,
138            length => u64::from_be_bytes(leading) >> (64 - length),
139        };
140        Ok(Self {
141            value,
142            length: length as u8,
143        })
144    }
145}
146
147/// Whether `octets` are the octets of a bit string of `length` bits: as many as the
148/// bits take, with zero bits after the last one.
149fn check_octets(octets: &[u8], length: usize) -> Result<(), Error> {
150    if octets.len() != length.div_ceil(8) {
151        return Err(Error::new(
152            ErrorKind::Argument,
153            format!(
154                "a bit string of {length} bits has {} octets, not {}",
155                length.div_ceil(8),
156                octets.len()
157            ),
158        ));
159    }
160    let unused = octets.len() * 8 - length;
161    if octets
162        .last()
163        .is_some_and(|last| last.trailing_zeros() < unused as u32)
164    {
165        return Err(Error::new(
166            ErrorKind::Argument,
167            format!(
168                "the last {unused} bits of the octets are after the {length} bits of the bit \
169                 string, and are not zero"
170            ),
171        ));
172    }
173    Ok(())
174}
175
176impl From<u8> for Bits {
177    fn from(value: u8) -> Self {
178        Self {
179            value: value.into(),
180            length: 8,
181        }
182    }
183}
184
185impl From<u16> for Bits {
186    fn from(value: u16) -> Self {
187        Self {
188            value: value.into(),
189            length: 16,
190        }
191    }
192}
193
194impl From<u32> for Bits {
195    fn from(value: u32) -> Self {
196        Self {
197            value: value.into(),
198            length: 32,
199        }
200    }
201}
202
203impl From<u64> for Bits {
204    fn from(value: u64) -> Self {
205        Self { value, length: 64 }
206    }
207}
208
209/// The number in hexadecimal, and the length: `0x155/10`.
210impl fmt::Debug for Bits {
211    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
212        write!(formatter, "{:#x}/{}", self.value, self.length)
213    }
214}
215
216/// A BIT STRING of any length: its octets, the last one padded with zero bits, and how
217/// many bits it has.
218///
219/// The octets are borrowed from what was decoded, or owned, as those of [`Octets`]. A
220/// string of 64 bits at most is held in the value itself, and never allocates.
221///
222/// ```
223/// use oxirush_aper::BitString;
224///
225/// // A key of 256 bits: every bit of its octets
226/// let key = BitString::from([0x5a; 32]);
227/// assert_eq!(key.len(), 256);
228/// assert_eq!(key.as_octets().len(), 32);
229///
230/// // A transport layer address of 20 bits has three octets
231/// let bits = BitString::new(vec![0xab, 0xcd, 0xe0], 20)?;
232/// assert_eq!(bits.get(0), Some(true));
233/// assert_eq!(bits.get(20), None);
234///
235/// // The bits after the last one are zero
236/// assert!(BitString::new(vec![0xab, 0xcd, 0xef], 20).is_err());
237/// # Ok::<(), oxirush_aper::Error>(())
238/// ```
239#[derive(Clone)]
240pub struct BitString<'a>(Held<'a>);
241
242#[derive(Clone)]
243enum Held<'a> {
244    /// 64 bits at most, from the first bit of the octets.
245    Short {
246        octets: [u8; 8],
247        length: u8,
248    },
249    Long {
250        octets: Octets<'a>,
251        length: usize,
252    },
253}
254
255impl<'a> BitString<'a> {
256    /// No bit.
257    pub const EMPTY: Self = Self(Held::Short {
258        octets: [0; 8],
259        length: 0,
260    });
261
262    /// The bit string of `length` bits that `octets` hold from their first bit.
263    ///
264    /// # Errors
265    ///
266    /// An error of the kind `Argument` for other octets than `length` bits take, and
267    /// for bits after the last one that are not zero.
268    pub fn new(octets: impl Into<Octets<'a>>, length: usize) -> Result<Self, Error> {
269        let octets = octets.into();
270        check_octets(&octets, length)?;
271        Ok(Self::of(octets, length))
272    }
273
274    /// The bit string that is every bit of `octets`.
275    pub fn from_octets(octets: impl Into<Octets<'a>>) -> Self {
276        let octets = octets.into();
277        let length = octets.len() * 8;
278        Self::of(octets, length)
279    }
280
281    /// The bit string of `length` bits whose octets are known to be those of such a
282    /// string.
283    pub(crate) fn of(octets: Octets<'a>, length: usize) -> Self {
284        debug_assert!(check_octets(&octets, length).is_ok());
285        if length > 64 {
286            return Self(Held::Long { octets, length });
287        }
288        let mut short = [0; 8];
289        short[..octets.len()].copy_from_slice(&octets);
290        Self(Held::Short {
291            octets: short,
292            length: length as u8,
293        })
294    }
295
296    /// How many bits the string has.
297    pub fn len(&self) -> usize {
298        match &self.0 {
299            Held::Short { length, .. } => usize::from(*length),
300            Held::Long { length, .. } => *length,
301        }
302    }
303
304    /// Whether the string has no bit.
305    pub fn is_empty(&self) -> bool {
306        self.len() == 0
307    }
308
309    /// The octets of the string, the last one padded with zero bits.
310    pub fn as_octets(&self) -> &[u8] {
311        match &self.0 {
312            Held::Short { octets, length } => &octets[..usize::from(*length).div_ceil(8)],
313            Held::Long { octets, .. } => octets,
314        }
315    }
316
317    /// The bit at a position, the first one at 0; `None` after the last.
318    pub fn get(&self, position: usize) -> Option<bool> {
319        if position >= self.len() {
320            return None;
321        }
322        Some(self.as_octets()[position / 8] & (0x80 >> (position % 8)) != 0)
323    }
324
325    /// The string as a number, when it has 64 bits at most.
326    pub fn to_bits(&self) -> Option<Bits> {
327        match &self.0 {
328            Held::Short { octets, length } => Some(Bits::low(
329                u64::from_be_bytes(*octets)
330                    .checked_shr(64 - u32::from(*length))
331                    .unwrap_or(0),
332                usize::from(*length),
333            )),
334            Held::Long { .. } => None,
335        }
336    }
337
338    /// The same string, with octets that it owns, kept as long as it is needed:
339    /// `BitString<'static>` is the type to write in a struct. The octets are copied
340    /// when they were borrowed.
341    #[doc(alias("to_owned", "owned", "keep"))]
342    pub fn into_owned(self) -> BitString<'static> {
343        BitString(match self.0 {
344            Held::Short { octets, length } => Held::Short { octets, length },
345            Held::Long { octets, length } => Held::Long {
346                octets: octets.into_owned(),
347                length,
348            },
349        })
350    }
351}
352
353impl Default for BitString<'_> {
354    fn default() -> Self {
355        Self::EMPTY
356    }
357}
358
359impl PartialEq for BitString<'_> {
360    fn eq(&self, other: &Self) -> bool {
361        self.len() == other.len() && self.as_octets() == other.as_octets()
362    }
363}
364
365impl Eq for BitString<'_> {}
366
367impl core::hash::Hash for BitString<'_> {
368    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
369        self.len().hash(state);
370        self.as_octets().hash(state);
371    }
372}
373
374impl PartialOrd for BitString<'_> {
375    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
376        Some(self.cmp(other))
377    }
378}
379
380/// By the bits, a string before those that it starts.
381impl Ord for BitString<'_> {
382    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
383        let octets = self.as_octets().cmp(other.as_octets());
384        octets.then(self.len().cmp(&other.len()))
385    }
386}
387
388impl<'a> From<&'a [u8]> for BitString<'a> {
389    fn from(octets: &'a [u8]) -> Self {
390        Self::from_octets(octets)
391    }
392}
393
394impl<'a, const N: usize> From<&'a [u8; N]> for BitString<'a> {
395    fn from(octets: &'a [u8; N]) -> Self {
396        Self::from_octets(octets)
397    }
398}
399
400impl From<Vec<u8>> for BitString<'_> {
401    fn from(octets: Vec<u8>) -> Self {
402        Self::from_octets(octets)
403    }
404}
405
406impl<const N: usize> From<[u8; N]> for BitString<'_> {
407    fn from(octets: [u8; N]) -> Self {
408        Self::from_octets(octets)
409    }
410}
411
412impl From<Bits> for BitString<'_> {
413    fn from(bits: Bits) -> Self {
414        Self(Held::Short {
415            octets: bits.leading(),
416            length: bits.len() as u8,
417        })
418    }
419}
420
421/// The octets in hexadecimal, and the length: `abcde0/20`.
422impl fmt::Debug for BitString<'_> {
423    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
424        write_hex(self.as_octets(), formatter)?;
425        write!(formatter, "/{}", self.len())
426    }
427}
428
429#[cfg(test)]
430mod tests {
431    use super::*;
432    use alloc::string::ToString;
433    use alloc::vec;
434
435    #[test]
436    fn a_short_bit_string_is_a_number_with_a_length() {
437        let set = Bits::new(0x155, 10).unwrap();
438        assert_eq!((set.value(), set.len()), (0x155, 10));
439        assert_eq!(set.to_vec(), [0x55, 0x40]);
440        assert_eq!(Bits::from_octets(&[0x55, 0x40], 10).unwrap(), set);
441        assert_eq!(set.get(0), Some(false));
442        assert_eq!(set.get(1), Some(true));
443        assert_eq!(set.get(9), Some(true));
444        assert_eq!(set.get(10), None);
445        assert_eq!(format!("{set:?}"), "0x155/10");
446
447        // Every length up to 64, and no other.
448        assert_eq!(Bits::new(0, 0).unwrap(), Bits::EMPTY);
449        assert!(Bits::EMPTY.is_empty());
450        assert!(Bits::EMPTY.to_vec().is_empty());
451        assert_eq!(Bits::new(u64::MAX, 64).unwrap(), Bits::from(u64::MAX));
452        assert_eq!(Bits::from(u64::MAX).to_vec(), [0xff; 8]);
453        assert_eq!(Bits::new(1, 65).unwrap_err().kind(), ErrorKind::Argument);
454        assert_eq!(Bits::new(1024, 10).unwrap_err().kind(), ErrorKind::Argument);
455        assert_eq!(
456            Bits::new(1024, 10).unwrap_err().to_string(),
457            "1024 does not fit in 10 bits"
458        );
459
460        // The least significant bits of a number.
461        assert_eq!(Bits::low(0xffff, 10), Bits::new(0x3ff, 10).unwrap());
462        assert_eq!(Bits::low(0xffff, 0), Bits::EMPTY);
463        assert_eq!(Bits::low(u64::MAX, 64), Bits::from(u64::MAX));
464        assert_eq!(Bits::low(u64::MAX, 99).len(), 64);
465
466        // Of the width of a number.
467        assert_eq!(Bits::from(0x80u8), Bits::new(0x80, 8).unwrap());
468        assert_eq!(Bits::from(0xe000u16).to_vec(), [0xe0, 0x00]);
469        assert_eq!(Bits::from(7u32).len(), 32);
470
471        // Octets that are not those of the string.
472        assert!(Bits::from_octets(&[0x55], 10).is_err());
473        assert!(Bits::from_octets(&[0x55, 0x41], 10).is_err());
474        assert!(Bits::from_octets(&[0; 9], 72).is_err());
475        assert_eq!(Bits::from_octets(&[], 0).unwrap(), Bits::EMPTY);
476    }
477
478    #[test]
479    fn a_long_bit_string_is_its_octets_with_a_length() {
480        let key = BitString::from([0x5a; 32]);
481        assert_eq!(key.len(), 256);
482        assert_eq!(key.to_bits(), None);
483
484        let bits = BitString::new(vec![0xab, 0xcd, 0xe0], 20).unwrap();
485        assert_eq!(bits.as_octets(), [0xab, 0xcd, 0xe0]);
486        assert_eq!(bits.get(0), Some(true));
487        assert_eq!(bits.get(1), Some(false));
488        assert_eq!(bits.get(19), Some(false));
489        assert_eq!(bits.get(20), None);
490        assert_eq!(format!("{bits:?}"), "abcde0/20");
491        assert_eq!(bits.to_bits(), Some(Bits::new(0xabcde, 20).unwrap()));
492        assert_eq!(BitString::from(Bits::new(0xabcde, 20).unwrap()), bits);
493
494        assert!(BitString::new(vec![0xab, 0xcd, 0xef], 20).is_err());
495        assert!(BitString::new(vec![0xab, 0xcd], 20).is_err());
496        assert!(BitString::default().is_empty());
497        assert_eq!(BitString::default(), BitString::EMPTY);
498
499        // A short string is the same whatever holds it.
500        let short = BitString::new(vec![0xff, 0x80], 9).unwrap();
501        assert_eq!(short, BitString::from(Bits::new(0x1ff, 9).unwrap()));
502        assert_eq!(short.to_bits(), Some(Bits::new(0x1ff, 9).unwrap()));
503        assert_eq!(BitString::EMPTY.to_bits(), Some(Bits::EMPTY));
504        assert_eq!(
505            BitString::from([0xffu8; 8]).to_bits(),
506            Some(Bits::from(u64::MAX))
507        );
508        assert!(BitString::new(vec![0xa0], 4).unwrap() < BitString::new(vec![0xa0], 8).unwrap());
509
510        let received = [0xffu8, 0x80];
511        let borrowed = BitString::new(&received[..], 9).unwrap();
512        let kept: BitString<'static> = borrowed.clone().into_owned();
513        assert_eq!(kept, borrowed);
514    }
515}