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 LGPL-2.1-or-later
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](https://users.rust-lang.org/t/extracting-static-associated-type-from-type-with-lifetime/126880)
63//! to bind the associated type to the error type of the
64//! [`CodesReaderFactory::CodesReader`]. The user can implement
65//! [`CodesReaderFactory`] on its own types and write trait bounds using
66//! [`CodesReaderFactoryHelper`]:
67//! ```ignore
68//! fn test<E: Endianness, CRF: CodesReaderFactoryHelper<E>>(factory: CRF)
69//! {
70//!     let reader = factory.new_reader();
71//!     // do something with the reader
72//!     // CRF::Error is the error type of CRF::CodesReader<'a>
73//! }
74//! ```
75
76use super::*;
77/// A trait that models a type that can return a [`CodesRead`] that can reference
78/// data owned by the factory. The typical case is a factory that owns the
79/// bit stream, and returns a [`CodesRead`] that can read from it.
80pub trait CodesReaderFactory<E: Endianness> {
81    type CodesReader<'a>
82    where
83        Self: 'a;
84
85    /// Creates a new code reader that can reference data owned by the factory.
86    fn new_reader(&self) -> Self::CodesReader<'_>;
87}
88
89/// Extension helper trait for [`CodesReaderFactory`].
90///
91/// By writing trait bounds using this helper instead of [`CodesReaderFactory`],
92/// you can access the error type of the [`CodesReaderFactory::CodesReader`] through
93/// [`CodesReaderFactoryHelper::Error`].
94pub trait CodesReaderFactoryHelper<E: Endianness>:
95    for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = Self::Error>>
96{
97    type Error;
98}
99
100impl<E: Endianness, F, ERR> CodesReaderFactoryHelper<E> for F
101where
102    F: ?Sized + for<'a> CodesReaderFactory<E, CodesReader<'a>: CodesRead<E, Error = ERR>>,
103{
104    type Error = ERR;
105}
106
107/// The function type stored in a [`FactoryFuncCodeReader`].
108///
109/// The role of this type is analogous to that of `ReadFn` in [`FuncCodeReader`],
110/// but we have an extra lifetime parameter to handle the lifetime
111/// of the [`CodesReaderFactory::CodesReader`].
112type FactoryReadFn<E, CRF> = for<'a> fn(
113    &mut <CRF as CodesReaderFactory<E>>::CodesReader<'a>,
114)
115    -> Result<u64, <CRF as CodesReaderFactoryHelper<E>>::Error>;
116
117/// A newtype depending on a [`CodesReaderFactory`] and containing a function
118/// pointer dispatching the read method for a code.
119///
120/// It is essentially a version of [`FuncCodeReader`] that depends on a
121/// [`CodesReaderFactory`] and its associated
122/// [`CodesReaderFactory::CodesReader`] instead of a generic [`CodesRead`].
123#[derive(Debug, Copy)]
124pub struct FactoryFuncCodeReader<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized>(
125    FactoryReadFn<E, CRF>,
126);
127
128/// Manually implement [`Clone`] to avoid the [`Clone`] bound on `CRF` and `E`.
129impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> Clone
130    for FactoryFuncCodeReader<E, CRF>
131{
132    #[inline(always)]
133    fn clone(&self) -> Self {
134        Self(self.0)
135    }
136}
137
138impl<E: Endianness, CRF: CodesReaderFactoryHelper<E> + ?Sized> FactoryFuncCodeReader<E, CRF> {
139    // due to the added lifetime generic we cannot just re-use the FuncCodeReader definitions
140    const UNARY: FactoryReadFn<E, CRF> = |reader| reader.read_unary();
141    const GAMMA: FactoryReadFn<E, CRF> = |reader| reader.read_gamma();
142    const DELTA: FactoryReadFn<E, CRF> = |reader| reader.read_delta();
143    const OMEGA: FactoryReadFn<E, CRF> = |reader| reader.read_omega();
144    const VBYTE_BE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_be();
145    const VBYTE_LE: FactoryReadFn<E, CRF> = |reader| reader.read_vbyte_le();
146    const ZETA2: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(2);
147    const ZETA3: FactoryReadFn<E, CRF> = |reader| reader.read_zeta3();
148    const ZETA4: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(4);
149    const ZETA5: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(5);
150    const ZETA6: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(6);
151    const ZETA7: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(7);
152    const ZETA8: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(8);
153    const ZETA9: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(9);
154    const ZETA10: FactoryReadFn<E, CRF> = |reader| reader.read_zeta(10);
155    const RICE1: FactoryReadFn<E, CRF> = |reader| reader.read_rice(1);
156    const RICE2: FactoryReadFn<E, CRF> = |reader| reader.read_rice(2);
157    const RICE3: FactoryReadFn<E, CRF> = |reader| reader.read_rice(3);
158    const RICE4: FactoryReadFn<E, CRF> = |reader| reader.read_rice(4);
159    const RICE5: FactoryReadFn<E, CRF> = |reader| reader.read_rice(5);
160    const RICE6: FactoryReadFn<E, CRF> = |reader| reader.read_rice(6);
161    const RICE7: FactoryReadFn<E, CRF> = |reader| reader.read_rice(7);
162    const RICE8: FactoryReadFn<E, CRF> = |reader| reader.read_rice(8);
163    const RICE9: FactoryReadFn<E, CRF> = |reader| reader.read_rice(9);
164    const RICE10: FactoryReadFn<E, CRF> = |reader| reader.read_rice(10);
165    const PI1: FactoryReadFn<E, CRF> = |reader| reader.read_pi(1);
166    const PI2: FactoryReadFn<E, CRF> = |reader| reader.read_pi2();
167    const PI3: FactoryReadFn<E, CRF> = |reader| reader.read_pi(3);
168    const PI4: FactoryReadFn<E, CRF> = |reader| reader.read_pi(4);
169    const PI5: FactoryReadFn<E, CRF> = |reader| reader.read_pi(5);
170    const PI6: FactoryReadFn<E, CRF> = |reader| reader.read_pi(6);
171    const PI7: FactoryReadFn<E, CRF> = |reader| reader.read_pi(7);
172    const PI8: FactoryReadFn<E, CRF> = |reader| reader.read_pi(8);
173    const PI9: FactoryReadFn<E, CRF> = |reader| reader.read_pi(9);
174    const PI10: FactoryReadFn<E, CRF> = |reader| reader.read_pi(10);
175    const GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(3);
176    const GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(5);
177    const GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(6);
178    const GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(7);
179    const GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(9);
180    const GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_golomb(10);
181    const EXP_GOLOMB1: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(1);
182    const EXP_GOLOMB2: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(2);
183    const EXP_GOLOMB3: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(3);
184    const EXP_GOLOMB4: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(4);
185    const EXP_GOLOMB5: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(5);
186    const EXP_GOLOMB6: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(6);
187    const EXP_GOLOMB7: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(7);
188    const EXP_GOLOMB8: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(8);
189    const EXP_GOLOMB9: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(9);
190    const EXP_GOLOMB10: FactoryReadFn<E, CRF> = |reader| reader.read_exp_golomb(10);
191
192    /// Returns a new [`FactoryFuncCodeReader`] for the given code.
193    ///
194    /// The code is [canonicalized](Codes::canonicalize) before
195    /// the lookup, so equivalent codes yield the same reader.
196    ///
197    /// # Errors
198    ///
199    /// The method will return an error if there is no constant
200    /// for the given code in [`FactoryFuncCodeReader`].
201    pub const fn new(code: Codes) -> Result<Self, DispatchError> {
202        let code = code.canonicalize();
203        let read_func = match code {
204            Codes::Unary => Self::UNARY,
205            Codes::Gamma => Self::GAMMA,
206            Codes::Delta => Self::DELTA,
207            Codes::Omega => Self::OMEGA,
208            Codes::VByteBe => Self::VBYTE_BE,
209            Codes::VByteLe => Self::VBYTE_LE,
210            Codes::Zeta(2) => Self::ZETA2,
211            Codes::Zeta(3) => Self::ZETA3,
212            Codes::Zeta(4) => Self::ZETA4,
213            Codes::Zeta(5) => Self::ZETA5,
214            Codes::Zeta(6) => Self::ZETA6,
215            Codes::Zeta(7) => Self::ZETA7,
216            Codes::Zeta(8) => Self::ZETA8,
217            Codes::Zeta(9) => Self::ZETA9,
218            Codes::Zeta(10) => Self::ZETA10,
219            Codes::Rice(1) => Self::RICE1,
220            Codes::Rice(2) => Self::RICE2,
221            Codes::Rice(3) => Self::RICE3,
222            Codes::Rice(4) => Self::RICE4,
223            Codes::Rice(5) => Self::RICE5,
224            Codes::Rice(6) => Self::RICE6,
225            Codes::Rice(7) => Self::RICE7,
226            Codes::Rice(8) => Self::RICE8,
227            Codes::Rice(9) => Self::RICE9,
228            Codes::Rice(10) => Self::RICE10,
229            Codes::Pi(1) => Self::PI1,
230            Codes::Pi(2) => Self::PI2,
231            Codes::Pi(3) => Self::PI3,
232            Codes::Pi(4) => Self::PI4,
233            Codes::Pi(5) => Self::PI5,
234            Codes::Pi(6) => Self::PI6,
235            Codes::Pi(7) => Self::PI7,
236            Codes::Pi(8) => Self::PI8,
237            Codes::Pi(9) => Self::PI9,
238            Codes::Pi(10) => Self::PI10,
239            Codes::Golomb(3) => Self::GOLOMB3,
240            Codes::Golomb(5) => Self::GOLOMB5,
241            Codes::Golomb(6) => Self::GOLOMB6,
242            Codes::Golomb(7) => Self::GOLOMB7,
243            Codes::Golomb(9) => Self::GOLOMB9,
244            Codes::Golomb(10) => Self::GOLOMB10,
245            Codes::ExpGolomb(1) => Self::EXP_GOLOMB1,
246            Codes::ExpGolomb(2) => Self::EXP_GOLOMB2,
247            Codes::ExpGolomb(3) => Self::EXP_GOLOMB3,
248            Codes::ExpGolomb(4) => Self::EXP_GOLOMB4,
249            Codes::ExpGolomb(5) => Self::EXP_GOLOMB5,
250            Codes::ExpGolomb(6) => Self::EXP_GOLOMB6,
251            Codes::ExpGolomb(7) => Self::EXP_GOLOMB7,
252            Codes::ExpGolomb(8) => Self::EXP_GOLOMB8,
253            Codes::ExpGolomb(9) => Self::EXP_GOLOMB9,
254            Codes::ExpGolomb(10) => Self::EXP_GOLOMB10,
255            _ => return Err(DispatchError::UnsupportedCode(code)),
256        };
257        Ok(Self(read_func))
258    }
259
260    /// Returns a new [`FactoryFuncCodeReader`] for the given function.
261    #[must_use]
262    #[inline(always)]
263    pub const fn new_with_func(read_func: FactoryReadFn<E, CRF>) -> Self {
264        Self(read_func)
265    }
266
267    /// Returns the function pointer for the code.
268    #[must_use]
269    #[inline(always)]
270    pub const fn get_func(&self) -> FactoryReadFn<E, CRF> {
271        self.0
272    }
273
274    /// Returns a [`FuncCodeReader`] compatible with `CRF`'s
275    /// [`CodesReaderFactory::CodesReader`] for a given lifetime `'a`.
276    #[must_use]
277    #[inline(always)]
278    pub const fn get<'a>(
279        &self,
280    ) -> super::FuncCodeReader<E, <CRF as CodesReaderFactory<E>>::CodesReader<'a>> {
281        super::FuncCodeReader::new_with_func(self.0)
282    }
283}