dsi_bitstream/traits/mod.rs
1/*
2 * SPDX-FileCopyrightText: 2023 Inria
3 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8/*!
9
10Traits for operating on streams of bits.
11
12We provide three bit-based traits, [`BitRead`], [`BitWrite`], and
13[`BitSeek`], analogous to [`std::io::Read`], [`std::io::Write`],
14and [`std::io::Seek`], respectively. They provide read/write operations
15on fixed-width blocks of bits and unary codes. More complex operations,
16such as [reading instantaneous codes](crate::codes::GammaReadParam),
17are built on these basic traits.
18
19The endianness of a bit stream specified by using the selector types
20[`BigEndian`] (AKA [`LE`]) and [`LittleEndian`] (AKA [`BE`]), which
21are the only implementations of the sealed marker trait [`Endianness`].
22
23The implementations we provide for these traits (e.g.,
24[`BufBitReader`](crate::impls::BufBitReader)) are based on
25[`WordRead`], [`WordWrite`], and [`WordSeek`], which provide word-based operations,
26as reading or writing multiple bytes at a time is usually much faster than
27reading or writing single bytes, in particular when interacting with memory.
28For example, [`MemWordRead`](crate::impls::MemWordReader) is a [`WordRead`]
29that reads word-by-word from a slice.
30
31All traits have an internal error type `Error`, which usually propagates the
32error of the underlying backend. However, in some cases (e.g., [`MemWordRead`](crate::impls::MemWordReader)
33with infinite zero extension) the error type is [`Infallible`](core::convert::Infallible),
34in which case the compiler is able to perform several further optimizations.
35
36Note that methods returning a [`Result`] will return a [`Result::Err`] variant
37only if there is an error in the underlying backend: errors in the parameters to the
38methods will generally result in panics.
39
40## Bit and byte order
41
42The endianness parameter specifies at the same byte the endianness of the byte
43stream and of the bits in each byte: in the little-endian case, the first bit
44of the stream is the least significant bit of the first byte, while in the
45big-endian case it is the most significant bit of the first byte. Albeit in principle
46one can mix independently the two orders, having the same order for both bytes
47and bits is usually more convenient and makes for more efficient implementations.
48
49Byte-level endianness is used to read memory word-by-word, greatly reducing the number
50of memory accesses when reading from slices. However, it is important to note that
51fixed-width values have thair least significant bit always stored at the lowest bit position,
52independently of endianness, as current CPUs always use big-endian bit order.
53In particular, reversing the order of the bits of each byte of a file containing
54a sequence of fixed-width integers or instantaneous codes
55will not in general yield a file containing the same sequence of integers or codes
56with the opposite endianness.
57
58For example, if we write just the value 6 to a big-endian bit stream, we will
59get as first byte `110xxxxx`, while if we write it to a little-endian bit stream
60we will obtain the byte `xxxxx110`. Clearly, reversing the order of the bits
61of each byte will not give the other byte.
62
63See the [codes](crate::codes) module for a discussion on the impact of
64endianness on the encoding of instantaneous codes.
65
66*/
67
68mod bits;
69pub use bits::*;
70
71mod words;
72pub use words::*;
73
74mod endianness;
75pub use endianness::*;