Skip to main content

oximedia_bitstream/
little_endian.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//! Little-endian `Endianness` implementation.
8//!
9//! Split out of `lib.rs` during the 0.1.4 refactor.
10
11use core::mem;
12use std::io;
13
14use crate::endian::{find_unary, read_byte, write_byte};
15use crate::{
16    private, BitCount, BitRead, BitWrite, Checked, CheckedSigned, CheckedUnsigned, Endianness,
17    Numeric, Primitive, SignedBitCount, SignedInteger, UnsignedInteger,
18};
19
20/// Little-endian, or least significant bits first
21#[derive(Copy, Clone, Debug)]
22pub struct LittleEndian;
23
24/// Little-endian, or least significant bits first
25pub type LE = LittleEndian;
26
27impl LittleEndian {
28    // checked in the sense that we've verified
29    // the output type is large enough to hold the
30    // requested number of bits
31    #[inline]
32    fn read_bits_checked<const MAX: u32, R, U>(
33        reader: &mut R,
34        queue: &mut u8,
35        queue_bits: &mut u32,
36        BitCount { bits }: BitCount<MAX>,
37    ) -> io::Result<U>
38    where
39        R: io::Read,
40        U: UnsignedInteger,
41    {
42        // reads a whole value with the given number of
43        // bytes in our endianness, where the number of bytes
44        // must be less than or equal to the type's size in bytes
45        #[inline(always)]
46        fn read_bytes<R, U>(reader: &mut R, bytes: usize) -> io::Result<U>
47        where
48            R: io::Read,
49            U: UnsignedInteger,
50        {
51            let mut buf = U::buffer();
52            reader
53                .read_exact(&mut buf.as_mut()[0..bytes])
54                .map(|()| U::from_le_bytes(buf))
55        }
56
57        if bits <= *queue_bits {
58            // all bits in queue, so no byte needed
59            let value = *queue & u8::ALL.shr_default(u8::BITS_SIZE - bits);
60            *queue = queue.shr_default(bits);
61            *queue_bits -= bits;
62            Ok(U::from_u8(value))
63        } else {
64            // at least one byte needed
65
66            // bits needed beyond what's in the queue
67            let needed_bits = bits - *queue_bits;
68
69            match (needed_bits / 8, needed_bits % 8) {
70                (0, needed) => {
71                    // only one additional byte needed,
72                    // which we share between our returned value
73                    // and the bit queue
74                    let next_byte = read_byte(reader)?;
75
76                    Ok(
77                        U::from_u8(mem::replace(queue, next_byte.shr_default(needed)))
78                            | (U::from_u8(next_byte & (u8::ALL >> (u8::BITS_SIZE - needed)))
79                                << mem::replace(queue_bits, u8::BITS_SIZE - needed)),
80                    )
81                }
82                (bytes, 0) => {
83                    // exact number of bytes needed beyond what's
84                    // available in the queue
85
86                    // so read a whole value from the reader
87                    // and prepend what's left of our queue onto it
88
89                    Ok(U::from_u8(mem::take(queue))
90                        | (read_bytes::<R, U>(reader, bytes as usize)? << mem::take(queue_bits)))
91                }
92                (bytes, needed) => {
93                    // read a whole value from the reader
94                    // prepend what's in the queue at the front of it
95                    // *and* append a partial byte at the end of it
96                    // while also updating the queue and its bit count
97
98                    let whole: U = read_bytes(reader, bytes as usize)?;
99                    let next_byte = read_byte(reader)?;
100
101                    Ok(
102                        U::from_u8(mem::replace(queue, next_byte.shr_default(needed)))
103                            | (whole << *queue_bits)
104                            | (U::from_u8(next_byte & (u8::ALL >> (u8::BITS_SIZE - needed)))
105                                << (mem::replace(queue_bits, u8::BITS_SIZE - needed) + bytes * 8)),
106                    )
107                }
108            }
109        }
110    }
111}
112
113impl Endianness for LittleEndian {}
114
115impl private::Endianness for LittleEndian {
116    #[inline]
117    fn push_bit_flush(queue_value: &mut u8, queue_bits: &mut u32, bit: bool) -> Option<u8> {
118        *queue_value |= u8::from(bit) << *queue_bits;
119        *queue_bits = (*queue_bits + 1) % 8;
120        (*queue_bits == 0).then(|| mem::take(queue_value))
121    }
122
123    #[inline]
124    fn read_bits<const MAX: u32, R, U>(
125        reader: &mut R,
126        queue_value: &mut u8,
127        queue_bits: &mut u32,
128        count @ BitCount { bits }: BitCount<MAX>,
129    ) -> io::Result<U>
130    where
131        R: io::Read,
132        U: UnsignedInteger,
133    {
134        if MAX <= U::BITS_SIZE || bits <= U::BITS_SIZE {
135            Self::read_bits_checked::<MAX, R, U>(reader, queue_value, queue_bits, count)
136        } else {
137            Err(io::Error::new(
138                io::ErrorKind::InvalidInput,
139                "excessive bits for type read",
140            ))
141        }
142    }
143
144    #[inline]
145    fn read_bits_fixed<const BITS: u32, R, U>(
146        reader: &mut R,
147        queue_value: &mut u8,
148        queue_bits: &mut u32,
149    ) -> io::Result<U>
150    where
151        R: io::Read,
152        U: UnsignedInteger,
153    {
154        const {
155            assert!(BITS <= U::BITS_SIZE, "excessive bits for type read");
156        }
157
158        Self::read_bits_checked::<BITS, R, U>(
159            reader,
160            queue_value,
161            queue_bits,
162            BitCount::new::<BITS>(),
163        )
164    }
165
166    // checked in the sense that we've verified
167    // the input type is large enough to hold the
168    // requested number of bits and that the value is
169    // not too large for those bits
170    #[inline]
171    fn write_bits_checked<const MAX: u32, W, U>(
172        writer: &mut W,
173        queue_value: &mut u8,
174        queue_bits: &mut u32,
175        CheckedUnsigned {
176            count: BitCount { bits },
177            value,
178        }: CheckedUnsigned<MAX, U>,
179    ) -> io::Result<()>
180    where
181        W: io::Write,
182        U: UnsignedInteger,
183    {
184        fn write_bytes<W, U>(writer: &mut W, bytes: usize, value: U) -> io::Result<()>
185        where
186            W: io::Write,
187            U: UnsignedInteger,
188        {
189            let buf = U::to_le_bytes(value);
190            writer.write_all(&buf.as_ref()[0..bytes])
191        }
192
193        // the amount of available bits in the queue
194        let available_bits = u8::BITS_SIZE - *queue_bits;
195
196        if bits < available_bits {
197            // all bits fit in queue, so no write needed
198            *queue_value |= U::to_u8(value.shl_default(*queue_bits));
199            *queue_bits += bits;
200            Ok(())
201        } else {
202            // at least one byte needs to be written
203
204            // bits beyond what can fit in the queue
205            let excess_bits = bits - available_bits;
206
207            match (excess_bits / 8, excess_bits % 8) {
208                (0, excess) => {
209                    // only one byte to be written,
210                    // while the excess bits are shared
211                    // between the written byte and the bit queue
212
213                    write_byte(
214                        writer,
215                        mem::replace(queue_value, U::to_u8(value.shr_default(available_bits)))
216                            | U::to_u8(
217                                (value << mem::replace(queue_bits, excess)) & U::from_u8(u8::ALL),
218                            ),
219                    )
220                }
221                (bytes, 0) => {
222                    // no excess bytes beyond what can fit the queue
223                    // so write a whole byte and
224                    // the remainder of the whole value
225
226                    write_byte(
227                        writer.by_ref(),
228                        mem::take(queue_value)
229                            | U::to_u8((value << mem::take(queue_bits)) & U::from_u8(u8::ALL)),
230                    )?;
231
232                    write_bytes(writer, bytes as usize, value >> available_bits)
233                }
234                (bytes, excess) => {
235                    // write what's in the queue along
236                    // with the head of our whole value,
237                    // write the middle section of our whole value,
238                    // while also replacing the queue with
239                    // the tail of our whole value
240
241                    write_byte(
242                        writer.by_ref(),
243                        mem::replace(
244                            queue_value,
245                            U::to_u8(value.shr_default(available_bits + bytes * 8)),
246                        ) | U::to_u8(
247                            (value << mem::replace(queue_bits, excess)) & U::from_u8(u8::ALL),
248                        ),
249                    )?;
250
251                    write_bytes(writer, bytes as usize, value >> available_bits)
252                }
253            }
254        }
255    }
256
257    fn write_signed_bits_checked<const MAX: u32, W, S>(
258        writer: &mut W,
259        queue_value: &mut u8,
260        queue_bits: &mut u32,
261        value: CheckedSigned<MAX, S>,
262    ) -> io::Result<()>
263    where
264        W: io::Write,
265        S: SignedInteger,
266    {
267        // little-endian
268        let (
269            SignedBitCount {
270                bits: BitCount { bits },
271                unsigned,
272            },
273            value,
274        ) = value.into_count_value();
275
276        Self::write_bits_checked(
277            writer.by_ref(),
278            queue_value,
279            queue_bits,
280            Checked {
281                value: if value.is_negative() {
282                    value.as_negative(bits)
283                } else {
284                    value.as_non_negative()
285                },
286                count: unsigned,
287            },
288        )?;
289        match Self::push_bit_flush(queue_value, queue_bits, value.is_negative()) {
290            Some(b) => write_byte(writer, b),
291            None => Ok(()),
292        }
293    }
294
295    #[inline]
296    fn pop_bit_refill<R>(
297        reader: &mut R,
298        queue_value: &mut u8,
299        queue_bits: &mut u32,
300    ) -> io::Result<bool>
301    where
302        R: io::Read,
303    {
304        Ok(if *queue_bits == 0 {
305            let value = read_byte(reader)?;
306            let lsb = value & u8::LSB_BIT;
307            *queue_value = value >> 1;
308            *queue_bits = u8::BITS_SIZE - 1;
309            lsb
310        } else {
311            let lsb = *queue_value & u8::LSB_BIT;
312            *queue_value >>= 1;
313            *queue_bits -= 1;
314            lsb
315        } != 0)
316    }
317
318    #[inline]
319    fn pop_unary<const STOP_BIT: u8, R>(
320        reader: &mut R,
321        queue_value: &mut u8,
322        queue_bits: &mut u32,
323    ) -> io::Result<u32>
324    where
325        R: io::Read,
326    {
327        const {
328            assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
329        }
330
331        match STOP_BIT {
332            0 => find_unary(
333                reader,
334                queue_value,
335                queue_bits,
336                |v| v.trailing_ones(),
337                |q| *q,
338                |v, b| v.checked_shr(b),
339            ),
340            1 => find_unary(
341                reader,
342                queue_value,
343                queue_bits,
344                |v| v.trailing_zeros(),
345                |_| u8::BITS_SIZE,
346                |v, b| v.checked_shr(b),
347            ),
348            _ => unreachable!(),
349        }
350    }
351
352    #[inline]
353    fn read_signed_counted<const MAX: u32, R, S>(
354        r: &mut R,
355        SignedBitCount {
356            bits: BitCount { bits },
357            unsigned,
358        }: SignedBitCount<MAX>,
359    ) -> io::Result<S>
360    where
361        R: BitRead,
362        S: SignedInteger,
363    {
364        if MAX <= S::BITS_SIZE || bits <= S::BITS_SIZE {
365            let unsigned = r.read_unsigned_counted::<MAX, S::Unsigned>(unsigned)?;
366            let is_negative = r.read_bit()?;
367            Ok(if is_negative {
368                unsigned.as_negative(bits)
369            } else {
370                unsigned.as_non_negative()
371            })
372        } else {
373            Err(io::Error::new(
374                io::ErrorKind::InvalidInput,
375                "excessive bits for type read",
376            ))
377        }
378    }
379
380    fn read_bytes<const CHUNK_SIZE: usize, R>(
381        reader: &mut R,
382        queue_value: &mut u8,
383        queue_bits: u32,
384        buf: &mut [u8],
385    ) -> io::Result<()>
386    where
387        R: io::Read,
388    {
389        if queue_bits == 0 {
390            reader.read_exact(buf)
391        } else {
392            let mut input_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
393
394            for output_chunk in buf.chunks_mut(CHUNK_SIZE) {
395                let input_chunk = &mut input_chunk[0..output_chunk.len()];
396                reader.read_exact(input_chunk)?;
397
398                output_chunk
399                    .iter_mut()
400                    .zip(input_chunk.iter())
401                    .for_each(|(o, i)| {
402                        *o = i << queue_bits;
403                    });
404
405                output_chunk[1..]
406                    .iter_mut()
407                    .zip(input_chunk.iter())
408                    .for_each(|(o, i)| {
409                        *o |= i >> (u8::BITS_SIZE - queue_bits);
410                    });
411
412                // `input_chunk` is `&input_chunk[0..output_chunk.len()]` and
413                // `chunks_mut` never yields an empty slice, so `last()` is always `Some`.
414                let last_byte = *input_chunk
415                    .last()
416                    .unwrap_or_else(|| unreachable!("chunks_mut never yields empty slices"));
417                output_chunk[0] |=
418                    mem::replace(queue_value, last_byte >> (u8::BITS_SIZE - queue_bits));
419            }
420
421            Ok(())
422        }
423    }
424
425    fn write_bytes<const CHUNK_SIZE: usize, W>(
426        writer: &mut W,
427        queue_value: &mut u8,
428        queue_bits: u32,
429        buf: &[u8],
430    ) -> io::Result<()>
431    where
432        W: io::Write,
433    {
434        if queue_bits == 0 {
435            writer.write_all(buf)
436        } else {
437            let mut output_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
438
439            for input_chunk in buf.chunks(CHUNK_SIZE) {
440                let output_chunk = &mut output_chunk[0..input_chunk.len()];
441
442                output_chunk
443                    .iter_mut()
444                    .zip(input_chunk.iter())
445                    .for_each(|(o, i)| {
446                        *o = i << queue_bits;
447                    });
448
449                output_chunk[1..]
450                    .iter_mut()
451                    .zip(input_chunk.iter())
452                    .for_each(|(o, i)| {
453                        *o |= i >> (u8::BITS_SIZE - queue_bits);
454                    });
455
456                // `input_chunk` is `buf.chunks(CHUNK_SIZE)[i]`; `chunks` never
457                // yields an empty slice, so `last()` is always `Some`.
458                let last_byte = *input_chunk
459                    .last()
460                    .unwrap_or_else(|| unreachable!("chunks never yields empty slices"));
461                output_chunk[0] |=
462                    mem::replace(queue_value, last_byte >> (u8::BITS_SIZE - queue_bits));
463
464                writer.write_all(output_chunk)?;
465            }
466
467            Ok(())
468        }
469    }
470
471    #[inline(always)]
472    fn bytes_to_primitive<P: Primitive>(buf: P::Bytes) -> P {
473        P::from_le_bytes(buf)
474    }
475
476    #[inline(always)]
477    fn primitive_to_bytes<P: Primitive>(p: P) -> P::Bytes {
478        p.to_le_bytes()
479    }
480
481    #[inline]
482    fn read_primitive<R, V>(r: &mut R) -> io::Result<V>
483    where
484        R: BitRead,
485        V: Primitive,
486    {
487        let mut buffer = V::buffer();
488        r.read_bytes(buffer.as_mut())?;
489        Ok(V::from_le_bytes(buffer))
490    }
491
492    #[inline]
493    fn write_primitive<W, V>(w: &mut W, value: V) -> io::Result<()>
494    where
495        W: BitWrite,
496        V: Primitive,
497    {
498        w.write_bytes(value.to_le_bytes().as_ref())
499    }
500}