Skip to main content

dsi_bitstream/dispatch/
factory.rs

1/*
2 * SPDX-FileCopyrightText: 2025 Tommaso Fontana
3 * SPDX-FileCopyrightText: 2025 Inria
4 * SPDX-FileCopyrightText: 2025 Sebastiano Vigna
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR MIT
7 */
8
9//! Dynamic-dispatching factories for readers with a lifetime.
10//!
11//! # Motivation
12//!
13//! [`FuncCodeReader`] already provides dynamic dispatching of read functions,
14//! but in some use cases the reader has to reference some data (e.g., readers
15//! based on the same memory buffer). In this case, one would need to create a
16//! dispatching function pointer for each code and each reader because the
17//! lifetime of different readers make the function pointers incompatible.
18//!
19//! The trait [`CodesReaderFactory`] solves this problem by providing a way to
20//! create a [`CodesRead`] with a lifetime that can reference data owned by the
21//! factory. This trait must be implemented by client applications.
22//!
23//! At that point, one can create a [`FactoryFuncCodeReader`] depending on a
24//! specific [`CodesReaderFactory`]. The [`FactoryFuncCodeReader`] will store a
25//! function pointer with a generic lifetime that can be downcast to a specific
26//! lifetime. Thus, the function pointer is created just once at the creation of
27//! the [`FactoryFuncCodeReader`], and can be reused to create
28//! [`FuncCodeReader`]s with any lifetime using [`FactoryFuncCodeReader::get`].
29//!
30//! # Implementation Notes
31//!
32//! In principle, we would like to have inside a [`FactoryFuncCodeReader`] a
33//! field with type
34//!
35//! ```ignore
36//! for<'a> FuncCodeReader<E, CRF::CodesReader<'a>>
37//! ```
38//!
39//! However, this is not possible in the Rust type system. We can however write
40//! the type
41//!
42//! ```ignore
43//! for<'a> fn(&mut CRF::CodesReader<'a>) -> Result<u64>
44//! ```
45//!
46//! This workaround is not perfect as we cannot properly specify the error type:
47//! ```ignore
48//! Result<u64, <CRF::CodesReader<'a> as BitRead<E>>::Error>
49//! ```
50//! The compiler here complains that the return type has a lifetime not
51//! constrained by the input arguments.
52//!
53//! To work around this problem, we could add an otherwise useless associated
54//! type `CodesReaderFactory::Error` to the [`CodesReaderFactory`] trait,
55//! imposing that the error type of [`CodesReaderFactory::CodesReader`] is the
56//! same. Unfortunately, this requires that all users of the factory add a `where`
57//! constraint in which the error type is written explicitly.
58//!
59//! To mitigate this problem, we provide instead a helper trait
60//! [`CodesReaderFactoryHelper`] that extends [`CodesReaderFactory`]; the helper
61//! trait contains an `Error` associated type and [uses higher-rank trait
62//! bounds] to bind the associated type to the error type of the
63//! [`CodesReaderFactory::CodesReader`]. The user can implement
64//! [`CodesReaderFactory`] on its own types and write trait bounds using
65//! [`CodesReaderFactoryHelper`]:
66//! ```ignore
67//! fn test<E: Endianness, CRF: CodesReaderFactoryHelper<E>>(factory: CRF)
68//! {
69//!     let reader = factory.new_reader();
70//!     // do something with the reader
71//!     // CRF::Error is the error type of CRF::CodesReader<'a>
72//! }
73//! ```
74//!
75//! [uses higher-rank trait bounds]: https://users.rust-lang.org/t/extracting-static-associated-type-from-type-with-lifetime/126880
76
77use super::*;
78/// A trait that models a type that can return a [`CodesRead`] that can reference
79/// data owned by the factory. The typical case is a factory that owns the
80/// bit stream, and returns a [`CodesRead`] that can read from it.
81pub trait CodesReaderFactory<E: Endianness> {
82    type CodesReader<'a>
83    where
84        Self: 'a;
85
86    /// Creates a new code reader that can reference data owned by the factory.
87    fn new_reader(&self) -> Self::CodesReader<'_>;
88}
89
90/// Extension helper trait for [`CodesReaderFactory`].
91///
92/// By writing trait bounds using this helper instead of [`CodesReaderFactory`],
93/// you can access the error type of the [`CodesReaderFactory::CodesReader`] through
94/// [`CodesReaderFactoryHelper::Error`].
95pub trait CodesReaderFactoryHelper<E: Endianness>:
96    for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = Self::Error>>
97{
98    type Error;
99}
100
101impl<E: Endianness, F, ERR> CodesReaderFactoryHelper<E> for F
102where
103    F: ?Sized + for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = ERR>>,
104{
105    type Error = ERR;
106}
107
108/// The function type stored in a [`FactoryFuncCodeReader`].
109///
110/// The role of this type is analogous to that of `ReadFn` in [`FuncCodeReader`],
111/// but we have an extra lifetime parameter to handle the lifetime
112/// of the [`CodesReaderFactory::CodesReader`].
113type FactoryReadFn<E, CRF> = for<'a> fn(
114    &mut <CRF as CodesReaderFactory<E>>::CodesReader<'a>,
115)
116    -> Result<u64, <CRF as CodesReaderFactoryHelper<E>>::Error>;
117
118/// A newtype depending on a [`CodesReaderFactory`] and containing a function
119/// pointer dispatching the read method for a code.
120///
121/// It is essentially a version of [`FuncCodeReader`] that depends on a
122/// [`CodesReaderFactory`] and its associated
123/// [`CodesReaderFactory::CodesReader`] instead of a generic [`CodesRead`].
124#[derive(Debug, Copy)]
125pub struct FactoryFuncCodeReader<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized>(
126    FactoryReadFn<E, CRF>,
127);
128
129/// Manually implement [`Clone`] to avoid the [`Clone`] bound on `CRF` and `E`.
130impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> Clone
131    for FactoryFuncCodeReader<E, CRF>
132{
133    #[inline(always)]
134    fn clone(&self) -> Self {
135        Self(self.0)
136    }
137}
138
139impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> FactoryFuncCodeReader<E, CRF> {
140    // due to the added lifetime generic we cannot just re-use the FuncCodeReader definitions
141    const UNARY: FactoryReadFn<E, CRF> = |reader| reader.read_unary();
142    const GAMMA: FactoryReadFn<E, CRF> = |reader| reader.read_gamma();
143    const DELTA: FactoryReadFn<E, CRF> = |reader| reader.read_delta();
144    const OMEGA: FactoryReadFn<E, CRF> = |reader| reader.read_omega();
145    const VBYTE_BE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_be();
146    const VBYTE_LE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_le();
147    const ZETA2: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(2);
148    const ZETA3: FactoryReadFn<E, CRF> = |reader| reader.read_zeta3();
149    const ZETA4: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(4);
150    const ZETA5: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(5);
151    const ZETA6: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(6);
152    const ZETA7: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(7);
153    const ZETA8: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(8);
154    const ZETA9: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(9);
155    const ZETA10: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(10);
156    const RICE1: FactoryReadFn<E, CRF> = |reader| reader.read_rice(1);
157    const RICE2: FactoryReadFn<E, CRF> = |reader| reader.read_rice(2);
158    const RICE3: FactoryReadFn<E, CRF> = |reader| reader.read_rice(3);
159    const RICE4: FactoryReadFn<E, CRF> = |reader| reader.read_rice(4);
160    const RICE5: FactoryReadFn<E, CRF> = |reader| reader.read_rice(5);
161    const RICE6: FactoryReadFn<E, CRF> = |reader| reader.read_rice(6);
162    const RICE7: FactoryReadFn<E, CRF> = |reader| reader.read_rice(7);
163    const RICE8: FactoryReadFn<E, CRF> = |reader| reader.read_rice(8);
164    const RICE9: FactoryReadFn<E, CRF> = |reader| reader.read_rice(9);
165    const RICE10: FactoryReadFn<E, CRF> = |reader| reader.read_rice(10);
166    const PI1: FactoryReadFn<E, CRF> = |reader| reader.read_pi(1);
167    const PI2: FactoryReadFn<E, CRF> = |reader| reader.read_pi2();
168    const PI3: FactoryReadFn<E, CRF> = |reader| reader.read_pi(3);
169    const PI4: FactoryReadFn<E, CRF> = |reader| reader.read_pi(4);
170    const PI5: FactoryReadFn<E, CRF> = |reader| reader.read_pi(5);
171    const PI6: FactoryReadFn<E, CRF> = |reader| reader.read_pi(6);
172    const PI7: FactoryReadFn<E, CRF> = |reader| reader.read_pi(7);
173    const PI8: FactoryReadFn<E, CRF> = |reader| reader.read_pi(8);
174    const PI9: FactoryReadFn<E, CRF> = |reader| reader.read_pi(9);
175    const PI10: FactoryReadFn<E, CRF> = |reader| reader.read_pi(10);
176    const GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(3);
177    const GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(5);
178    const GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(6);
179    const GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(7);
180    const GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(9);
181    const GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(10);
182    const EXP_GOLOMB1: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(1);
183    const EXP_GOLOMB2: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(2);
184    const EXP_GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(3);
185    const EXP_GOLOMB4: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(4);
186    const EXP_GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(5);
187    const EXP_GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(6);
188    const EXP_GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(7);
189    const EXP_GOLOMB8: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(8);
190    const EXP_GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(9);
191    const EXP_GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(10);
192
193    /// Returns a new [`FactoryFuncCodeReader`] for the given code.
194    ///
195    /// The code is [canonicalized] before the lookup, so equivalent codes yield
196    /// the same reader.
197    ///
198    /// # Errors
199    ///
200    /// The method will return an error if there is no constant
201    /// for the given code in [`FactoryFuncCodeReader`].
202    ///
203    /// [canonicalized]: Codes::canonicalize
204    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
205        let code = code.canonicalize();
206        let read_func = match code {
207            Codes::Unary => Self::UNARY,
208            Codes::Gamma => Self::GAMMA,
209            Codes::Delta => Self::DELTA,
210            Codes::Omega => Self::OMEGA,
211            Codes::VByteBe => Self::VBYTE_BE,
212            Codes::VByteLe => Self::VBYTE_LE,
213            Codes::Zeta(2) => Self::ZETA2,
214            Codes::Zeta(3) => Self::ZETA3,
215            Codes::Zeta(4) => Self::ZETA4,
216            Codes::Zeta(5) => Self::ZETA5,
217            Codes::Zeta(6) => Self::ZETA6,
218            Codes::Zeta(7) => Self::ZETA7,
219            Codes::Zeta(8) => Self::ZETA8,
220            Codes::Zeta(9) => Self::ZETA9,
221            Codes::Zeta(10) => Self::ZETA10,
222            Codes::Rice(1) => Self::RICE1,
223            Codes::Rice(2) => Self::RICE2,
224            Codes::Rice(3) => Self::RICE3,
225            Codes::Rice(4) => Self::RICE4,
226            Codes::Rice(5) => Self::RICE5,
227            Codes::Rice(6) => Self::RICE6,
228            Codes::Rice(7) => Self::RICE7,
229            Codes::Rice(8) => Self::RICE8,
230            Codes::Rice(9) => Self::RICE9,
231            Codes::Rice(10) => Self::RICE10,
232            Codes::Pi(1) => Self::PI1,
233            Codes::Pi(2) => Self::PI2,
234            Codes::Pi(3) => Self::PI3,
235            Codes::Pi(4) => Self::PI4,
236            Codes::Pi(5) => Self::PI5,
237            Codes::Pi(6) => Self::PI6,
238            Codes::Pi(7) => Self::PI7,
239            Codes::Pi(8) => Self::PI8,
240            Codes::Pi(9) => Self::PI9,
241            Codes::Pi(10) => Self::PI10,
242            Codes::Golomb(3) => Self::GOLOMB3,
243            Codes::Golomb(5) => Self::GOLOMB5,
244            Codes::Golomb(6) => Self::GOLOMB6,
245            Codes::Golomb(7) => Self::GOLOMB7,
246            Codes::Golomb(9) => Self::GOLOMB9,
247            Codes::Golomb(10) => Self::GOLOMB10,
248            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
249            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
250            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
251            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
252            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
253            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
254            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
255            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
256            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
257            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
258            _ => return Err(DispatchError::UnsupportedCode(code)),
259        };
260        Ok(Self(read_func))
261    }
262
263    /// Returns a new [`FactoryFuncCodeReader`] for the given function.
264    #[must_use]
265    #[inline(always)]
266    pub const fn new_with_func(read_func: FactoryReadFn<E, CRF>) -> Self {
267        Self(read_func)
268    }
269
270    /// Returns the function pointer for the code.
271    #[must_use]
272    #[inline(always)]
273    pub const fn get_func(&self) -> FactoryReadFn<E, CRF> {
274        self.0
275    }
276
277    /// Returns a [`FuncCodeReader`] compatible with `CRF`'s
278    /// [`CodesReaderFactory::CodesReader`] for a given lifetime `'a`.
279    #[must_use]
280    #[inline(always)]
281    pub const fn get<'a>(
282        &self,
283    ) -> super::FuncCodeReader<E, <CRF as CodesReaderFactory<E>>::CodesReader<'a>> {
284        super::FuncCodeReader::new_with_func(self.0)
285    }
286}