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}