@@ -2127,6 +2127,11 @@ impl<const MAX: u32, U: UnsignedInteger> CheckedUnsigned<MAX, U> {
21272127/// let v3 = r.read_checked::<FourBits>(FixedBitCount).unwrap();
21282128/// let v4 = r.read_checked::<FourBits>(FixedBitCount).unwrap();
21292129///
2130+ /// assert_eq!(v1.into_value(), 0b0001);
2131+ /// assert_eq!(v2.into_value(), 0b1111);
2132+ /// assert_eq!(v3.into_value(), 0b0110);
2133+ /// assert_eq!(v4.into_value(), 0b1001);
2134+ ///
21302135/// // write those same values back to disk
21312136/// let mut w = BitWriter::endian(vec![], BigEndian);
21322137/// w.write_checked(v1).unwrap();
@@ -2160,7 +2165,7 @@ impl<const BITS: u32, const MAX: u32> core::convert::TryFrom<BitCount<MAX>>
21602165pub type CheckedUnsignedFixed < const BITS : u32 , T > = Checked < FixedBitCount < BITS > , T > ;
21612166
21622167impl < const BITS : u32 , U : UnsignedInteger > CheckedUnsignedFixed < BITS , U > {
2163- /// Returns our value if it fits in the given number of const bits
2168+ /// Returns our checked value if it fits in the given number of const bits
21642169 ///
21652170 /// # Examples
21662171 ///
@@ -2178,7 +2183,7 @@ impl<const BITS: u32, U: UnsignedInteger> CheckedUnsignedFixed<BITS, U> {
21782183 /// ```
21792184 ///
21802185 /// ```compile_fail
2181- /// use bitstream_io::{BitCount, CheckedUnsignedFixed} ;
2186+ /// use bitstream_io::CheckedUnsignedFixed;
21822187 ///
21832188 /// // a bit count of 9 is too large for u8
21842189 ///
@@ -2285,6 +2290,7 @@ impl<const MAX: u32, S: SignedInteger> CheckablePrimitive for CheckedSigned<MAX,
22852290}
22862291
22872292impl < const MAX : u32 , S : SignedInteger > private:: Checkable for CheckedSigned < MAX , S > {
2293+ #[ inline]
22882294 fn write_endian < E , W > (
22892295 self ,
22902296 writer : & mut W ,
@@ -2389,6 +2395,164 @@ impl<const MAX: u32, S: SignedInteger> CheckedSigned<MAX, S> {
23892395 }
23902396}
23912397
2398+ /// A fixed number of bits to be consumed or written
2399+ ///
2400+ /// Analagous to [`SignedBitCount`], this is a zero-sized type
2401+ /// whose value is fixed at compile-time and cannot be changed.
2402+ ///
2403+ /// # Example
2404+ ///
2405+ /// ```
2406+ /// use bitstream_io::{
2407+ /// BigEndian, BitRead, BitReader, BitWrite, BitWriter,
2408+ /// CheckedSignedFixed, FixedSignedBitCount,
2409+ /// };
2410+ ///
2411+ /// type FourBits = CheckedSignedFixed<4, i8>;
2412+ ///
2413+ /// let input: &[u8] = &[0b0001_1111, 0b0110_1001];
2414+ /// let mut r = BitReader::endian(input, BigEndian);
2415+ ///
2416+ /// // read 4, 4-bit values
2417+ /// let v1 = r.read_checked::<FourBits>(FixedSignedBitCount).unwrap();
2418+ /// let v2 = r.read_checked::<FourBits>(FixedSignedBitCount).unwrap();
2419+ /// let v3 = r.read_checked::<FourBits>(FixedSignedBitCount).unwrap();
2420+ /// let v4 = r.read_checked::<FourBits>(FixedSignedBitCount).unwrap();
2421+ ///
2422+ /// assert_eq!(v1.into_value(), 1);
2423+ /// assert_eq!(v2.into_value(), -1);
2424+ /// assert_eq!(v3.into_value(), 6);
2425+ /// assert_eq!(v4.into_value(), -7);
2426+ ///
2427+ /// // write those same values back to disk
2428+ /// let mut w = BitWriter::endian(vec![], BigEndian);
2429+ /// w.write_checked(v1).unwrap();
2430+ /// w.write_checked(v2).unwrap();
2431+ /// w.write_checked(v3).unwrap();
2432+ /// w.write_checked(v4).unwrap();
2433+ ///
2434+ /// // ensure they're the same
2435+ /// assert_eq!(w.into_writer().as_slice(), input);
2436+ /// ```
2437+ #[ derive( Copy , Clone , Debug ) ]
2438+ pub struct FixedSignedBitCount < const BITS : u32 > ;
2439+
2440+ impl < const BITS : u32 > From < FixedSignedBitCount < BITS > > for SignedBitCount < BITS > {
2441+ fn from ( _count : FixedSignedBitCount < BITS > ) -> Self {
2442+ SignedBitCount :: new :: < BITS > ( )
2443+ }
2444+ }
2445+
2446+ impl < const BITS : u32 , const MAX : u32 > core:: convert:: TryFrom < SignedBitCount < MAX > >
2447+ for FixedSignedBitCount < BITS >
2448+ {
2449+ type Error = SignedBitCount < MAX > ;
2450+
2451+ fn try_from ( count : SignedBitCount < MAX > ) -> Result < Self , Self :: Error > {
2452+ ( count. bits . bits == BITS )
2453+ . then_some ( FixedSignedBitCount )
2454+ . ok_or ( count)
2455+ }
2456+ }
2457+
2458+ /// A signed type with a verified value for a fixed number of bits
2459+ pub type CheckedSignedFixed < const BITS : u32 , T > = Checked < FixedSignedBitCount < BITS > , T > ;
2460+
2461+ impl < const BITS : u32 , S : SignedInteger > CheckedSignedFixed < BITS , S > {
2462+ /// Returns our checked value if it fits in the given number of const bits
2463+ ///
2464+ /// # Examples
2465+ ///
2466+ /// ```
2467+ /// use bitstream_io::{SignedBitCount, CheckedSignedFixed, CheckedError};
2468+ ///
2469+ /// // a value of 3 fits into a 3 bit count
2470+ /// assert!(CheckedSignedFixed::<3, _>::new_fixed(3i8).is_ok());
2471+ ///
2472+ /// // a value of 4 does not fit into a 3 bit count
2473+ /// assert!(matches!(
2474+ /// CheckedSignedFixed::<3, _>::new_fixed(4i8),
2475+ /// Err(CheckedError::ExcessiveValue),
2476+ /// ));
2477+ /// ```
2478+ ///
2479+ /// ```compile_fail
2480+ /// use bitstream_io::CheckedSignedFixed;
2481+ ///
2482+ /// // a bit count of 9 is too large for i8
2483+ ///
2484+ /// // because this is checked at compile-time,
2485+ /// // it does not compile at all
2486+ /// let c = CheckedSignedFixed::<9, _>::new_fixed(1i8);
2487+ /// ```
2488+ pub fn new_fixed ( value : S ) -> Result < Self , CheckedError > {
2489+ const {
2490+ assert ! ( BITS <= S :: BITS_SIZE , "excessive bits for type written" ) ;
2491+ }
2492+
2493+ if BITS == S :: BITS_SIZE
2494+ || ( ( ( S :: ZERO - S :: ONE ) << ( BITS - 1 ) ) <= value && value < ( S :: ONE << ( BITS - 1 ) ) )
2495+ {
2496+ Ok ( Self {
2497+ count : FixedSignedBitCount ,
2498+ value,
2499+ } )
2500+ } else {
2501+ Err ( CheckedError :: ExcessiveValue )
2502+ }
2503+ }
2504+ }
2505+ impl < const BITS : u32 , S : SignedInteger > Checkable for CheckedSignedFixed < BITS , S > {
2506+ #[ inline]
2507+ fn write < W : BitWrite + ?Sized > ( & self , writer : & mut W ) -> io:: Result < ( ) > {
2508+ // a naive default implementation
2509+ writer. write_signed :: < BITS , _ > ( self . value )
2510+ }
2511+
2512+ #[ inline]
2513+ fn written_bits ( & self ) -> u32 {
2514+ BITS
2515+ }
2516+ }
2517+
2518+ impl < const BITS : u32 , S : SignedInteger > private:: Checkable for CheckedSignedFixed < BITS , S > {
2519+ #[ inline]
2520+ fn write_endian < E , W > (
2521+ self ,
2522+ writer : & mut W ,
2523+ queue_value : & mut u8 ,
2524+ queue_bits : & mut u32 ,
2525+ ) -> io:: Result < ( ) >
2526+ where
2527+ E : private:: Endianness ,
2528+ W : io:: Write ,
2529+ {
2530+ E :: write_signed_bits_checked (
2531+ writer,
2532+ queue_value,
2533+ queue_bits,
2534+ CheckedSigned {
2535+ value : self . value ,
2536+ count : self . count . into ( ) ,
2537+ } ,
2538+ )
2539+ }
2540+ }
2541+
2542+ impl < const BITS : u32 , S : SignedInteger > CheckablePrimitive for CheckedSignedFixed < BITS , S > {
2543+ type CountType = FixedSignedBitCount < BITS > ;
2544+
2545+ fn read < R : BitRead + ?Sized > (
2546+ reader : & mut R ,
2547+ count : FixedSignedBitCount < BITS > ,
2548+ ) -> std:: io:: Result < Self > {
2549+ Ok ( Self {
2550+ value : reader. read_signed :: < BITS , _ > ( ) ?,
2551+ count,
2552+ } )
2553+ }
2554+ }
2555+
23922556/// A trait for writable types whose values can be validated
23932557///
23942558/// Ordinarily, when writing a value to a stream with a given
0 commit comments