Skip to main content

oximedia_bitstream/
bitcount.rs

1// Copyright 2017 Brian Langenberger
2// Copyright 2024-2026 COOLJAPAN OU (Team Kitasan)
3//
4// Licensed under the Apache License, Version 2.0 or the MIT license,
5// at your option. See the LICENSE-APACHE / LICENSE-MIT files for details.
6
7//! `BitCount` and `SignedBitCount` — runtime bit-count values that track
8//! their statically known maximum at the type level.
9//!
10//! Moved here from `lib.rs` during the 0.1.4 refactor so the crate root
11//! stays under the COOLJAPAN 2 000-line guideline.
12
13use crate::{Checked, CheckedUnsigned, Numeric, SignedInteger, UnsignedInteger};
14
15/// A number of bits to be consumed or written, with a known maximum
16///
17/// Although [`crate::BitRead::read`] and [`crate::BitWrite::write`] should be
18/// preferred when the number of bits is fixed and known at compile-time -
19/// because they can validate the bit count is less than or equal
20/// to the type's size in bits at compile-time -
21/// there are many instances where bit count is dynamic and
22/// determined by the file format itself.
23/// But when using [`crate::BitRead::read_var`] or [`crate::BitWrite::write_var`]
24/// we must pessimistically assume any number of bits as an argument
25/// and validate that the number of bits is not larger than the
26/// type being read or written on every call.
27///
28/// ```
29/// use oximedia_bitstream::{BitRead, BitReader, BigEndian};
30///
31/// let data: &[u8] = &[0b100_0001_1, 0b111_0110_0];
32/// let mut r = BitReader::endian(data, BigEndian);
33/// // our bit count is a 3 bit value
34/// let count = r.read::<3, u32>().unwrap();
35/// // that count indicates we need to read 4 bits (0b100)
36/// assert_eq!(count, 4);
37/// // read the first 4-bit value
38/// assert_eq!(r.read_var::<u8>(count).unwrap(), 0b0001);
39/// // read the second 4-bit value
40/// assert_eq!(r.read_var::<u8>(count).unwrap(), 0b1111);
41/// // read the third 4-bit value
42/// assert_eq!(r.read_var::<u8>(count).unwrap(), 0b0110);
43/// ```
44///
45/// In the preceding example, even though we know `count` is a
46/// 3 bit value whose maximum value will never be greater than 7,
47/// the subsequent `read_var` calls have no way to know that.
48/// They must assume `count` could be 9, or `u32::MAX` or any other `u32` value
49/// and validate the count is not larger than the `u8` types we're reading.
50///
51/// But we can convert our example to use the `BitCount` type:
52///
53/// ```
54/// use oximedia_bitstream::{BitRead, BitReader, BigEndian, BitCount};
55///
56/// let data: &[u8] = &[0b100_0001_1, 0b111_0110_0];
57/// let mut r = BitReader::endian(data, BigEndian);
58/// // our bit count is a 3 bit value with a maximum value of 7
59/// let count = r.read_count::<0b111>().unwrap();
60/// // that count indicates we need to read 4 bits (0b100)
61/// assert_eq!(count, BitCount::<7>::new::<4>());
62/// // read the first 4-bit value
63/// assert_eq!(r.read_counted::<7, u8>(count).unwrap(), 0b0001);
64/// // read the second 4-bit value
65/// assert_eq!(r.read_counted::<7, u8>(count).unwrap(), 0b1111);
66/// // read the third 4-bit value
67/// assert_eq!(r.read_counted::<7, u8>(count).unwrap(), 0b0110);
68/// ```
69///
70/// Because the [`crate::BitRead::read_counted`] methods know at compile-time
71/// that the bit count will be larger than 7, that check can be eliminated
72/// simply by taking advantage of information we already know.
73///
74/// Leveraging the `BitCount` type also allows us to reason about
75/// bit counts in a more formal way, and use checked permutation methods
76/// to modify them while ensuring they remain constrained by
77/// the file format's requirements.
78#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
79pub struct BitCount<const MAX: u32> {
80    // The amount of bits may be less than or equal to the maximum,
81    // but never more.
82    pub(crate) bits: u32,
83}
84
85impl<const MAX: u32> BitCount<MAX> {
86    /// Builds a bit count from a constant number
87    /// of bits, which must not be greater than `MAX`.
88    ///
89    /// Intended to be used for defining constants.
90    ///
91    /// Use `TryFrom` to conditionally build
92    /// counts from values at runtime.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use oximedia_bitstream::{BitReader, BitRead, BigEndian, BitCount};
98    /// let data: &[u8] = &[0b111_00000];
99    /// let mut r = BitReader::endian(data, BigEndian);
100    /// // reading 3 bits from a stream out of a maximum of 8
101    /// // doesn't require checking that the bit count is larger
102    /// // than a u8 at runtime because specifying the maximum of 8
103    /// // guarantees our bit count will not be larger than 8
104    /// assert_eq!(r.read_counted::<8, u8>(BitCount::new::<3>()).unwrap(), 0b111);
105    /// ```
106    ///
107    /// ```rust,compile_fail
108    /// use oximedia_bitstream::BitCount;
109    /// // trying to build a count of 10 with a maximum of 8
110    /// // fails to compile at all
111    /// let count = BitCount::<8>::new::<10>();
112    /// ```
113    pub const fn new<const BITS: u32>() -> Self {
114        const {
115            assert!(BITS <= MAX, "BITS must be <= MAX");
116        }
117
118        Self { bits: BITS }
119    }
120
121    /// Add a number of bits to our count,
122    /// returning a new count with a new maximum.
123    ///
124    /// Returns `None` if the new count goes above our new maximum.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use oximedia_bitstream::BitCount;
130    ///
131    /// let count = BitCount::<2>::new::<1>();
132    /// // adding 2 to 1 and increasing the max to 3 yields a new count of 3
133    /// assert_eq!(count.checked_add::<3>(2), Some(BitCount::<3>::new::<3>()));
134    /// // adding 2 to 1 without increasing the max yields None
135    /// assert_eq!(count.checked_add::<2>(2), None);
136    /// ```
137    #[inline]
138    pub const fn checked_add<const NEW_MAX: u32>(self, bits: u32) -> Option<BitCount<NEW_MAX>> {
139        match self.bits.checked_add(bits) {
140            Some(bits) if bits <= NEW_MAX => Some(BitCount { bits }),
141            _ => None,
142        }
143    }
144
145    /// Subtracts a number of bits from our count,
146    /// returning a new count with a new maximum.
147    ///
148    /// Returns `None` if the new count goes below 0
149    /// or below our new maximum.
150    ///
151    /// # Example
152    /// ```
153    /// use oximedia_bitstream::BitCount;
154    /// let count = BitCount::<5>::new::<5>();
155    /// // subtracting 1 from 5 yields a new count of 4
156    /// assert_eq!(count.checked_sub::<5>(1), Some(BitCount::<5>::new::<4>()));
157    /// // subtracting 6 from 5 yields None
158    /// assert!(count.checked_sub::<5>(6).is_none());
159    /// // subtracting 1 with a new maximum of 3 also yields None
160    /// // because 4 is larger than the maximum of 3
161    /// assert!(count.checked_sub::<3>(1).is_none());
162    /// ```
163    #[inline]
164    pub const fn checked_sub<const NEW_MAX: u32>(self, bits: u32) -> Option<BitCount<NEW_MAX>> {
165        match self.bits.checked_sub(bits) {
166            Some(bits) if bits <= NEW_MAX => Some(BitCount { bits }),
167            _ => None,
168        }
169    }
170
171    /// Attempt to convert our count to a count with a new
172    /// bit count and new maximum.
173    ///
174    /// Returns `Some(count)` if the updated number of bits
175    /// is less than or equal to the new maximum.
176    /// Returns `None` if not.
177    ///
178    /// # Examples
179    /// ```
180    /// use oximedia_bitstream::BitCount;
181    ///
182    /// let count = BitCount::<5>::new::<5>();
183    /// // muliplying 5 bits by 2 with a new max of 10 is ok
184    /// assert_eq!(
185    ///     count.try_map::<10, _>(|i| i.checked_mul(2)),
186    ///     Some(BitCount::<10>::new::<10>()),
187    /// );
188    ///
189    /// // multiplying 5 bits by 3 with a new max of 10 overflows
190    /// assert_eq!(count.try_map::<10, _>(|i| i.checked_mul(3)), None);
191    /// ```
192    #[inline]
193    pub fn try_map<const NEW_MAX: u32, F>(self, f: F) -> Option<BitCount<NEW_MAX>>
194    where
195        F: FnOnce(u32) -> Option<u32>,
196    {
197        f(self.bits)
198            .filter(|bits| *bits <= NEW_MAX)
199            .map(|bits| BitCount { bits })
200    }
201
202    /// Returns our maximum bit count
203    ///
204    /// # Example
205    /// ```
206    /// use oximedia_bitstream::BitCount;
207    ///
208    /// let count = BitCount::<10>::new::<5>();
209    /// assert_eq!(count.max(), 10);
210    /// ```
211    #[inline(always)]
212    pub const fn max(&self) -> u32 {
213        MAX
214    }
215
216    /// Returns signed count if our bit count is greater than 0
217    ///
218    /// # Example
219    ///
220    /// ```
221    /// use oximedia_bitstream::{BitCount, SignedBitCount};
222    ///
223    /// let count = BitCount::<10>::new::<5>();
224    /// assert_eq!(count.signed_count(), Some(SignedBitCount::<10>::new::<5>()));
225    ///
226    /// let count = BitCount::<10>::new::<0>();
227    /// assert_eq!(count.signed_count(), None);
228    /// ```
229    #[inline(always)]
230    pub const fn signed_count(&self) -> Option<SignedBitCount<MAX>> {
231        match self.bits.checked_sub(1) {
232            Some(bits) => Some(SignedBitCount {
233                bits: *self,
234                unsigned: BitCount { bits },
235            }),
236            None => None,
237        }
238    }
239
240    /// Masks off the least-significant bits for the given type
241    ///
242    /// Returns closure that takes a value and returns a
243    /// pair of the most-significant and least-significant
244    /// bits.  Because the least-significant bits cannot
245    /// be larger than this bit count, that value is
246    /// returned as a [`Checked`] type.
247    ///
248    /// # Examples
249    ///
250    /// ```
251    /// use oximedia_bitstream::BitCount;
252    ///
253    /// // create a bit count of 3
254    /// let count = BitCount::<8>::new::<3>();
255    ///
256    /// // create a mask suitable for u8 types
257    /// let mask = count.mask_lsb::<u8>();
258    ///
259    /// let (msb, lsb) = mask(0b11011_110);
260    /// assert_eq!(msb, 0b11011);             // the most-significant bits
261    /// assert_eq!(lsb.into_value(), 0b110);  // the least-significant bits
262    ///
263    /// let (msb, lsb) = mask(0b01100_010);
264    /// assert_eq!(msb, 0b01100);             // the most-significant bits
265    /// assert_eq!(lsb.into_value(), 0b010);  // the least-significant bits
266    ///
267    /// let (msb, lsb) = mask(0b00000_111);
268    /// assert_eq!(msb, 0b00000);             // the most-significant bits
269    /// assert_eq!(lsb.into_value(), 0b111);  // the least-significant bits
270    /// ```
271    ///
272    /// ```
273    /// use oximedia_bitstream::BitCount;
274    ///
275    /// // a mask with a bit count of 0 puts everything in msb
276    /// let mask = BitCount::<8>::new::<0>().mask_lsb::<u8>();
277    ///
278    /// let (msb, lsb) = mask(0b11111111);
279    /// assert_eq!(msb, 0b11111111);
280    /// assert_eq!(lsb.into_value(), 0);
281    ///
282    /// // a mask with a bit count larger than the type
283    /// // is restricted to that type's size, if possible
284    /// let mask = BitCount::<16>::new::<9>().mask_lsb::<u8>();
285    ///
286    /// let (msb, lsb) = mask(0b11111111);
287    /// assert_eq!(msb, 0);
288    /// assert_eq!(lsb.into_value(), 0b11111111);
289    /// ```
290    pub fn mask_lsb<U: UnsignedInteger>(self) -> impl Fn(U) -> (U, CheckedUnsigned<MAX, U>) {
291        let (mask, shift, count) = match U::BITS_SIZE.checked_sub(self.bits) {
292            Some(mask_bits) => (U::ALL.shr_default(mask_bits), self.bits, self),
293            None => (
294                U::ALL,
295                U::BITS_SIZE,
296                // `self.bits > U::BITS_SIZE` (the `checked_sub` returned `None`), and
297                // `self.bits <= MAX`, so `MAX > U::BITS_SIZE >= U::BITS_SIZE`, meaning
298                // `BitCount::<MAX>` is valid for `U::BITS_SIZE`.  Construct directly to
299                // avoid a fallible conversion that cannot actually fail here.
300                BitCount { bits: U::BITS_SIZE },
301            ),
302        };
303
304        move |v| {
305            (
306                v.shr_default(shift),
307                Checked {
308                    value: v & mask,
309                    count,
310                },
311            )
312        }
313    }
314
315    /// Returns this bit count's range for the given unsigned type
316    ///
317    /// # Example
318    ///
319    /// ```
320    /// use oximedia_bitstream::BitCount;
321    ///
322    /// assert_eq!(BitCount::<9>::new::<0>().range::<u8>(), 0..=0);
323    /// assert_eq!(BitCount::<9>::new::<1>().range::<u8>(), 0..=0b1);
324    /// assert_eq!(BitCount::<9>::new::<2>().range::<u8>(), 0..=0b11);
325    /// assert_eq!(BitCount::<9>::new::<3>().range::<u8>(), 0..=0b111);
326    /// assert_eq!(BitCount::<9>::new::<4>().range::<u8>(), 0..=0b1111);
327    /// assert_eq!(BitCount::<9>::new::<5>().range::<u8>(), 0..=0b11111);
328    /// assert_eq!(BitCount::<9>::new::<6>().range::<u8>(), 0..=0b111111);
329    /// assert_eq!(BitCount::<9>::new::<7>().range::<u8>(), 0..=0b1111111);
330    /// assert_eq!(BitCount::<9>::new::<8>().range::<u8>(), 0..=0b11111111);
331    /// // a count that exceeds the type's size is
332    /// // naturally restricted to that type's maximum range
333    /// assert_eq!(BitCount::<9>::new::<9>().range::<u8>(), 0..=0b11111111);
334    /// ```
335    #[inline]
336    pub fn range<U: UnsignedInteger>(&self) -> core::ops::RangeInclusive<U> {
337        match U::ONE.checked_shl(self.bits) {
338            Some(top) => U::ZERO..=(top - U::ONE),
339            None => U::ZERO..=U::ALL,
340        }
341    }
342
343    /// Returns minimum value between ourself and bit count
344    ///
345    /// # Example
346    ///
347    /// ```
348    /// use oximedia_bitstream::BitCount;
349    ///
350    /// let count = BitCount::<8>::new::<7>();
351    /// assert_eq!(count.min(6), BitCount::new::<6>());
352    /// assert_eq!(count.min(8), BitCount::new::<7>());
353    /// ```
354    #[inline(always)]
355    pub fn min(self, bits: u32) -> Self {
356        // the minimum of ourself and another bit count
357        // can never exceed our maximum bit count
358        Self {
359            bits: self.bits.min(bits),
360        }
361    }
362
363    /// Returns the minimum value of an unsigned int in this bit count
364    ///
365    /// # Example
366    ///
367    /// ```
368    /// use oximedia_bitstream::BitCount;
369    ///
370    /// assert_eq!(BitCount::<8>::new::<0>().none::<u8>().into_value(), 0b0);
371    /// assert_eq!(BitCount::<8>::new::<1>().none::<u8>().into_value(), 0b0);
372    /// assert_eq!(BitCount::<8>::new::<2>().none::<u8>().into_value(), 0b00);
373    /// assert_eq!(BitCount::<8>::new::<3>().none::<u8>().into_value(), 0b000);
374    /// assert_eq!(BitCount::<8>::new::<4>().none::<u8>().into_value(), 0b0000);
375    /// assert_eq!(BitCount::<8>::new::<5>().none::<u8>().into_value(), 0b00000);
376    /// assert_eq!(BitCount::<8>::new::<6>().none::<u8>().into_value(), 0b000000);
377    /// assert_eq!(BitCount::<8>::new::<7>().none::<u8>().into_value(), 0b0000000);
378    /// assert_eq!(BitCount::<8>::new::<8>().none::<u8>().into_value(), 0b00000000);
379    /// ```
380    #[inline(always)]
381    pub fn none<U: UnsignedInteger>(self) -> CheckedUnsigned<MAX, U> {
382        CheckedUnsigned {
383            value: U::ZERO,
384            count: self,
385        }
386    }
387
388    /// Returns the maximum value of an unsigned int in this bit count
389    ///
390    /// # Example
391    ///
392    /// ```
393    /// use oximedia_bitstream::BitCount;
394    ///
395    /// assert_eq!(BitCount::<8>::new::<0>().all::<u8>().into_value(), 0b0);
396    /// assert_eq!(BitCount::<8>::new::<1>().all::<u8>().into_value(), 0b1);
397    /// assert_eq!(BitCount::<8>::new::<2>().all::<u8>().into_value(), 0b11);
398    /// assert_eq!(BitCount::<8>::new::<3>().all::<u8>().into_value(), 0b111);
399    /// assert_eq!(BitCount::<8>::new::<4>().all::<u8>().into_value(), 0b1111);
400    /// assert_eq!(BitCount::<8>::new::<5>().all::<u8>().into_value(), 0b11111);
401    /// assert_eq!(BitCount::<8>::new::<6>().all::<u8>().into_value(), 0b111111);
402    /// assert_eq!(BitCount::<8>::new::<7>().all::<u8>().into_value(), 0b1111111);
403    /// assert_eq!(BitCount::<8>::new::<8>().all::<u8>().into_value(), 0b11111111);
404    /// ```
405    #[inline(always)]
406    pub fn all<U: UnsignedInteger>(self) -> CheckedUnsigned<MAX, U> {
407        CheckedUnsigned {
408            value: match U::ONE.checked_shl(self.bits) {
409                Some(top) => top - U::ONE,
410                None => U::ALL,
411            },
412            count: self,
413        }
414    }
415}
416
417impl<const MAX: u32> core::convert::TryFrom<u32> for BitCount<MAX> {
418    type Error = u32;
419
420    /// Attempts to convert a `u32` bit count to a `BitCount`
421    ///
422    /// Attempting a bit maximum bit count larger than the
423    /// largest supported type is a compile-time error
424    ///
425    /// # Examples
426    /// ```
427    /// use oximedia_bitstream::BitCount;
428    /// use std::convert::TryInto;
429    ///
430    /// assert_eq!(8u32.try_into(), Ok(BitCount::<8>::new::<8>()));
431    /// assert_eq!(9u32.try_into(), Err::<BitCount<8>, _>(9));
432    /// ```
433    fn try_from(bits: u32) -> Result<Self, Self::Error> {
434        (bits <= MAX).then_some(Self { bits }).ok_or(bits)
435    }
436}
437
438impl<const MAX: u32> core::fmt::Display for BitCount<MAX> {
439    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
440        core::fmt::Display::fmt(&self.bits, f)
441    }
442}
443
444impl BitCount<{ u32::MAX }> {
445    /// Builds a bit count where the maximum bits is unknown.
446    ///
447    /// # Example
448    /// ```
449    /// use oximedia_bitstream::BitCount;
450    /// assert_eq!(BitCount::unknown(5), BitCount::<{ u32::MAX }>::new::<5>());
451    /// ```
452    pub const fn unknown(bits: u32) -> Self {
453        Self { bits }
454    }
455}
456
457#[test]
458fn test_unknown_bitcount() {
459    let count = BitCount::unknown(u32::MAX);
460    assert!(u32::from(count) <= count.max());
461}
462
463impl<const MAX: u32> From<BitCount<MAX>> for u32 {
464    #[inline(always)]
465    fn from(BitCount { bits }: BitCount<MAX>) -> u32 {
466        bits
467    }
468}
469
470/// A number of bits to be read or written for signed integers, with a known maximum
471///
472/// This is closely related to the [`BitCount`] type, but further constrained
473/// to have a minimum value of 1 - because signed values require at least
474/// 1 bit for the sign.
475///
476/// Let's start with a basic example:
477///
478/// ```
479/// use oximedia_bitstream::{BitRead, BitReader, BigEndian};
480///
481/// let data: &[u8] = &[0b100_0001_1, 0b111_0110_0];
482/// let mut r = BitReader::endian(data, BigEndian);
483/// // our bit count is a 3 bit value
484/// let count = r.read::<3, u32>().unwrap();
485/// // that count indicates we need to read 4 bits (0b100)
486/// assert_eq!(count, 4);
487/// // read the first 4-bit signed value
488/// assert_eq!(r.read_var::<i8>(count).unwrap(), 1);
489/// // read the second 4-bit signed value
490/// assert_eq!(r.read_var::<i8>(count).unwrap(), -1);
491/// // read the third 4-bit signed value
492/// assert_eq!(r.read_var::<i8>(count).unwrap(), 6);
493/// ```
494///
495/// In the preceding example, even though we know `count` is a
496/// 3 bit value whose maximum value will never be greater than 7,
497/// the subsequent `read_var` calls have no way to know that.
498/// They must assume `count` could be 9, or `u32::MAX` or any other `u32` value
499/// and validate the count is not larger than the `i8` types we're reading
500/// while also greater than 0 because `i8` requires a sign bit.
501///
502/// But we can convert our example to use the `SignedBitCount` type:
503/// ```
504/// use oximedia_bitstream::{BitRead, BitReader, BigEndian, SignedBitCount};
505///
506/// let data: &[u8] = &[0b100_0001_1, 0b111_0110_0];
507/// let mut r = BitReader::endian(data, BigEndian);
508/// // our bit count is a 3 bit value with a maximum value of 7
509/// let count = r.read_count::<0b111>().unwrap();
510/// // convert that count to a signed bit count,
511/// // which guarantees its value is greater than 0
512/// let count = count.signed_count().unwrap();
513/// // that count indicates we need to read 4 bits (0b100)
514/// assert_eq!(count, SignedBitCount::<7>::new::<4>());
515/// // read the first 4-bit value
516/// assert_eq!(r.read_signed_counted::<7, i8>(count).unwrap(), 1);
517/// // read the second 4-bit value
518/// assert_eq!(r.read_signed_counted::<7, i8>(count).unwrap(), -1);
519/// // read the third 4-bit value
520/// assert_eq!(r.read_signed_counted::<7, i8>(count).unwrap(), 6);
521/// ```
522///
523/// Because the [`crate::BitRead::read_signed_counted`] methods know at compile-time
524/// that the bit count will be larger than 7, that check can be eliminated
525/// simply by taking advantage of information we already know.
526///
527/// Leveraging the `SignedBitCount` type also allows us to reason about
528/// bit counts in a more formal way, and use checked permutation methods
529/// to modify them while ensuring they remain constrained by
530/// the file format's requirements.
531#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
532pub struct SignedBitCount<const MAX: u32> {
533    // the whole original bit count
534    pub(crate) bits: BitCount<MAX>,
535    // a bit count with one bit removed for the sign
536    pub(crate) unsigned: BitCount<MAX>,
537}
538
539impl<const MAX: u32> SignedBitCount<MAX> {
540    /// Builds a signed bit count from a constant number
541    /// of bits, which must be greater than 0 and
542    /// not be greater than `MAX`.
543    ///
544    /// Intended to be used for defining constants.
545    ///
546    /// Use `TryFrom` to conditionally build
547    /// counts from values at runtime.
548    ///
549    /// # Examples
550    ///
551    /// ```
552    /// use oximedia_bitstream::{BitReader, BitRead, BigEndian, SignedBitCount};
553    /// let data: &[u8] = &[0b111_00000];
554    /// let mut r = BitReader::endian(data, BigEndian);
555    /// // reading 3 bits from a stream out of a maximum of 8
556    /// // doesn't require checking that the bit count is larger
557    /// // than a u8 at runtime because specifying the maximum of 8
558    /// // guarantees our bit count will not be larger than 8
559    /// assert_eq!(r.read_signed_counted::<8, i8>(SignedBitCount::new::<3>()).unwrap(), -1);
560    /// ```
561    ///
562    /// ```rust,compile_fail
563    /// use oximedia_bitstream::SignedBitCount;
564    /// // trying to build a count of 10 with a maximum of 8
565    /// // fails to compile at all
566    /// let count = SignedBitCount::<8>::new::<10>();
567    /// ```
568    ///
569    /// ```rust,compile_fail
570    /// use oximedia_bitstream::SignedBitCount;
571    /// // trying to build a count of 0 also fails to compile
572    /// let count = SignedBitCount::<8>::new::<0>();
573    /// ```
574    pub const fn new<const BITS: u32>() -> Self {
575        const {
576            assert!(BITS > 0, "BITS must be > 0");
577        }
578
579        Self {
580            bits: BitCount::new::<BITS>(),
581            unsigned: BitCount { bits: BITS - 1 },
582        }
583    }
584
585    /// Add a number of bits to our count,
586    /// returning a new count with a new maximum.
587    ///
588    /// Returns `None` if the new count goes above our new maximum.
589    ///
590    /// # Examples
591    ///
592    /// ```
593    /// use oximedia_bitstream::SignedBitCount;
594    ///
595    /// let count = SignedBitCount::<2>::new::<1>();
596    /// // adding 2 to 1 and increasing the max to 3 yields a new count of 3
597    /// assert_eq!(count.checked_add::<3>(2), Some(SignedBitCount::<3>::new::<3>()));
598    /// // adding 2 to 1 without increasing the max yields None
599    /// assert_eq!(count.checked_add::<2>(2), None);
600    /// ```
601    #[inline]
602    pub const fn checked_add<const NEW_MAX: u32>(
603        self,
604        bits: u32,
605    ) -> Option<SignedBitCount<NEW_MAX>> {
606        match self.bits.checked_add(bits) {
607            Some(bits_new) => match self.unsigned.checked_add(bits) {
608                Some(unsigned) => Some(SignedBitCount {
609                    bits: bits_new,
610                    unsigned,
611                }),
612                None => None,
613            },
614            None => None,
615        }
616    }
617
618    /// Subtracts a number of bits from our count,
619    /// returning a new count with a new maximum.
620    ///
621    /// Returns `None` if the new count goes below 1
622    /// or below our new maximum.
623    ///
624    /// # Example
625    /// ```
626    /// use oximedia_bitstream::SignedBitCount;
627    /// let count = SignedBitCount::<5>::new::<5>();
628    /// // subtracting 1 from 5 yields a new count of 4
629    /// assert_eq!(count.checked_sub::<5>(1), Some(SignedBitCount::<5>::new::<4>()));
630    /// // subtracting 6 from 5 yields None
631    /// assert!(count.checked_sub::<5>(6).is_none());
632    /// // subtracting 1 with a new maximum of 3 also yields None
633    /// // because 4 is larger than the maximum of 3
634    /// assert!(count.checked_sub::<3>(1).is_none());
635    /// // subtracting 5 from 5 also yields None
636    /// // because SignedBitCount always requires 1 bit for the sign
637    /// assert!(count.checked_sub::<5>(5).is_none());
638    /// ```
639    #[inline]
640    pub const fn checked_sub<const NEW_MAX: u32>(
641        self,
642        bits: u32,
643    ) -> Option<SignedBitCount<NEW_MAX>> {
644        match self.bits.checked_sub(bits) {
645            Some(bits_new) => match self.unsigned.checked_sub(bits) {
646                Some(unsigned) => Some(SignedBitCount {
647                    bits: bits_new,
648                    unsigned,
649                }),
650                None => None,
651            },
652            None => None,
653        }
654    }
655
656    /// Attempt to convert our count to a count with a new
657    /// bit count and new maximum.
658    ///
659    /// Returns `Some(count)` if the updated number of bits
660    /// is less than or equal to the new maximum
661    /// and greater than 0.
662    /// Returns `None` if not.
663    ///
664    /// # Examples
665    /// ```
666    /// use oximedia_bitstream::SignedBitCount;
667    ///
668    /// let count = SignedBitCount::<5>::new::<5>();
669    /// // muliplying 5 bits by 2 with a new max of 10 is ok
670    /// assert_eq!(
671    ///     count.try_map::<10, _>(|i| i.checked_mul(2)),
672    ///     Some(SignedBitCount::<10>::new::<10>()),
673    /// );
674    ///
675    /// // multiplying 5 bits by 3 with a new max of 10 overflows
676    /// assert_eq!(count.try_map::<10, _>(|i| i.checked_mul(3)), None);
677    ///
678    /// // multiplying 5 bits by 0 results in 0 bits,
679    /// // which isn't value for a SignedBitCount
680    /// assert_eq!(count.try_map::<10, _>(|i| Some(i * 0)), None);
681    /// ```
682    #[inline]
683    pub fn try_map<const NEW_MAX: u32, F>(self, f: F) -> Option<SignedBitCount<NEW_MAX>>
684    where
685        F: FnOnce(u32) -> Option<u32>,
686    {
687        self.bits.try_map(f).and_then(|b| b.signed_count())
688    }
689
690    /// Returns our maximum bit count
691    ///
692    /// # Example
693    /// ```
694    /// use oximedia_bitstream::SignedBitCount;
695    ///
696    /// let count = SignedBitCount::<10>::new::<5>();
697    /// assert_eq!(count.max(), 10);
698    /// ```
699    #[inline(always)]
700    pub const fn max(&self) -> u32 {
701        MAX
702    }
703
704    /// Returns regular unsigned bit count
705    ///
706    /// # Example
707    ///
708    /// ```
709    /// use oximedia_bitstream::{BitCount, SignedBitCount};
710    ///
711    /// let signed_count = SignedBitCount::<10>::new::<5>();
712    /// assert_eq!(signed_count.count(), BitCount::<10>::new::<5>());
713    /// ```
714    #[inline(always)]
715    pub const fn count(&self) -> BitCount<MAX> {
716        self.bits
717    }
718
719    /// Returns this bit count's range for the given signed type
720    ///
721    /// # Example
722    ///
723    /// ```
724    /// use oximedia_bitstream::SignedBitCount;
725    ///
726    /// assert_eq!(SignedBitCount::<9>::new::<1>().range::<i8>(), -1..=0);
727    /// assert_eq!(SignedBitCount::<9>::new::<2>().range::<i8>(), -2..=1);
728    /// assert_eq!(SignedBitCount::<9>::new::<3>().range::<i8>(), -4..=3);
729    /// assert_eq!(SignedBitCount::<9>::new::<4>().range::<i8>(), -8..=7);
730    /// assert_eq!(SignedBitCount::<9>::new::<5>().range::<i8>(), -16..=15);
731    /// assert_eq!(SignedBitCount::<9>::new::<6>().range::<i8>(), -32..=31);
732    /// assert_eq!(SignedBitCount::<9>::new::<7>().range::<i8>(), -64..=63);
733    /// assert_eq!(SignedBitCount::<9>::new::<8>().range::<i8>(), -128..=127);
734    /// // a count that exceeds the type's size is
735    /// // naturally restricted to that type's maximum range
736    /// assert_eq!(SignedBitCount::<9>::new::<9>().range::<i8>(), -128..=127);
737    /// ```
738    pub fn range<S: SignedInteger>(&self) -> core::ops::RangeInclusive<S> {
739        // a bit of a hack to get around the somewhat restrictive
740        // SignedInteger trait I've created for myself
741
742        if self.bits.bits < S::BITS_SIZE {
743            (!S::ZERO << self.unsigned.bits)..=((S::ONE << self.unsigned.bits) - S::ONE)
744        } else {
745            S::Unsigned::ZERO.as_negative(S::BITS_SIZE)..=(S::Unsigned::ALL >> 1).as_non_negative()
746        }
747    }
748}
749
750impl<const MAX: u32> core::fmt::Display for SignedBitCount<MAX> {
751    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
752        core::fmt::Display::fmt(&self.bits, f)
753    }
754}
755
756impl<const MAX: u32> core::convert::TryFrom<BitCount<MAX>> for SignedBitCount<MAX> {
757    type Error = ();
758
759    #[inline]
760    fn try_from(count: BitCount<MAX>) -> Result<Self, Self::Error> {
761        count.signed_count().ok_or(())
762    }
763}
764
765impl<const MAX: u32> core::convert::TryFrom<u32> for SignedBitCount<MAX> {
766    type Error = u32;
767
768    #[inline]
769    fn try_from(count: u32) -> Result<Self, Self::Error> {
770        BitCount::<MAX>::try_from(count).and_then(|b| b.signed_count().ok_or(count))
771    }
772}
773
774impl<const MAX: u32> From<SignedBitCount<MAX>> for u32 {
775    #[inline(always)]
776    fn from(
777        SignedBitCount {
778            bits: BitCount { bits },
779            ..
780        }: SignedBitCount<MAX>,
781    ) -> u32 {
782        bits
783    }
784}