dsi_bitstream/traits/words.rs
1/*
2 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
3 * SPDX-FileCopyrightText: 2023 Inria
4 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
7 */
8
9use core::error::Error;
10
11use num_primitive::PrimitiveUnsigned;
12
13/// This is a convenience trait bundling the bounds required for words read and
14/// written by either a [`WordRead`] or [`WordWrite`], respectively.
15///
16/// We provide `ZERO` and `ONE` associated constants to avoid depending on
17/// [`num-traits`](https://crates.io/crates/num-traits)'s
18/// [`ConstZero`](https://docs.rs/num-traits/latest/num_traits/identities/trait.ConstZero.html)
19/// and
20/// [`ConstOne`](https://docs.rs/num-traits/latest/num_traits/identities/trait.ConstOne.html).
21pub trait Word: PrimitiveUnsigned {
22 const ZERO: Self;
23 const ONE: Self;
24}
25
26macro_rules! impl_word {
27 ($($t:ty),*) => {
28 $(
29 impl Word for $t {
30 const ZERO: Self = 0;
31 const ONE: Self = 1;
32 }
33 )*
34 };
35}
36
37impl_word!(u8, u16, u32, u64, u128, usize);
38
39/// Trait providing the double-width type for a given unsigned integer type.
40///
41/// This is used by [`crate::impls::BufBitReader`] to provide a bit buffer
42/// that is twice the width of the word read from the backend.
43///
44/// The methods
45/// [`as_double`](Self::as_double)/[`as_u64`](Self::as_u64) can be
46/// used to convert a word into its double-width type or to a `u64`,
47/// respectively, without loss of precision.
48pub trait DoubleType {
49 type DoubleType: Word;
50
51 /// Converts a word into its double-width type without loss of precision.
52 fn as_double(&self) -> Self::DoubleType;
53
54 /// Converts a word into a `u64` without loss of precision.
55 fn as_u64(&self) -> u64;
56}
57
58macro_rules! impl_double_type {
59 ($($t:ty => $d:ty),*) => {
60 $(
61 impl DoubleType for $t {
62 type DoubleType = $d;
63
64 fn as_double(&self) -> Self::DoubleType {
65 *self as Self::DoubleType
66 }
67
68 fn as_u64(&self) -> u64 {
69 *self as u64
70 }
71 }
72 )*
73 };
74}
75
76impl_double_type!(
77 u8 => u16,
78 u16 => u32,
79 u32 => u64,
80 u64 => u128
81);
82
83/// Sequential, streaming word-by-word reads.
84pub trait WordRead {
85 type Error: Error + Send + Sync + 'static;
86
87 /// The word type (the type of the result of [`WordRead::read_word`]).
88 type Word: Word;
89
90 /// Reads a word and advances the current position.
91 fn read_word(&mut self) -> Result<Self::Word, Self::Error>;
92}
93
94/// Sequential, streaming word-by-word writes.
95pub trait WordWrite {
96 type Error: Error + Send + Sync + 'static;
97
98 /// The word type (the type of the argument of [`WordWrite::write_word`]).
99 type Word: Word;
100
101 /// Writes a word and advances the current position.
102 fn write_word(&mut self, word: Self::Word) -> Result<(), Self::Error>;
103
104 /// Flushes the stream.
105 fn flush(&mut self) -> Result<(), Self::Error>;
106}
107
108/// Seekability for [`WordRead`] and [`WordWrite`] streams.
109pub trait WordSeek {
110 type Error: Error + Send + Sync + 'static;
111 /// Gets the current position in words from the start of the stream.
112 ///
113 /// Note that, consistently with
114 /// [`Seek::stream_position`](https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position),
115 /// this method takes a mutable reference to `self`.
116 fn word_pos(&mut self) -> Result<u64, Self::Error>;
117
118 /// Sets the current position in words from the start of the stream to `word_pos`.
119 fn set_word_pos(&mut self, word_pos: u64) -> Result<(), Self::Error>;
120}
121
122/// Replacement of [`std::io::Error`] for `no_std` environments.
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
124pub enum WordError {
125 UnexpectedEof { word_pos: usize },
126}
127
128impl core::error::Error for WordError {}
129impl core::fmt::Display for WordError {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 match self {
132 WordError::UnexpectedEof { word_pos } => {
133 write!(f, "unexpected end of data at word position {}", word_pos)
134 }
135 }
136 }
137}