jxl_oxide_common/
lib.rs

1//! Common helpers used in various places of jxl-oxide.
2//!
3//! This crate is mainly for internal use.
4
5use jxl_bitstream::Bitstream;
6
7#[macro_export]
8#[doc(hidden)]
9macro_rules! expand_u32 {
10    ($bitstream:ident; $($rest:tt)*) => {
11        $crate::expand_u32!(@convert $bitstream; (); ($($rest)*,))
12    };
13    (@convert $bitstream:ident; ($($done:tt)*); ()) => {
14        $bitstream.read_u32($($done)*)
15    };
16    (@convert $bitstream:ident; ($($done:tt)*); ($c:literal, $($rest:tt)*)) => {
17        $crate::expand_u32!(@convert $bitstream; ($($done)* $c,); ($($rest)*))
18    };
19    (@convert $bitstream:ident; ($($done:tt)*); (u($n:literal), $($rest:tt)*)) => {
20        $crate::expand_u32!(@convert $bitstream; ($($done)* ::jxl_bitstream::U($n),); ($($rest)*))
21    };
22    (@convert $bitstream:ident; ($($done:tt)*); ($c:literal + u($n:literal), $($rest:tt)*)) => {
23        $crate::expand_u32!(@convert $bitstream; ($($done)* $c + ::jxl_bitstream::U($n),); ($($rest)*))
24    };
25}
26
27#[macro_export]
28#[doc(hidden)]
29macro_rules! read_bits {
30    ($bistream:ident, $c:literal $(, $ctx:expr)?) => {
31        ::jxl_bitstream::BitstreamResult::Ok($c)
32    };
33    ($bitstream:ident, u($n:literal) $(, $ctx:expr)?) => {
34        $bitstream.read_bits($n)
35    };
36    ($bitstream:ident, u($n:literal); UnpackSigned $(, $ctx:expr)?) => {
37        $bitstream.read_bits($n).map(::jxl_bitstream::unpack_signed)
38    };
39    ($bitstream:ident, $c:literal + u($n:literal) $(, $ctx:expr)?) => {
40        $bitstream.read_bits($n).map(|v| v.wrapping_add($c))
41    };
42    ($bitstream:ident, $c:literal + u($n:literal); UnpackSigned $(, $ctx:expr)?) => {
43        $bitstream.read_bits($n).map(|v| ::jxl_bitstream::unpack_signed(v.wrapping_add($c)))
44    };
45    ($bitstream:ident, U32($($args:tt)+) $(, $ctx:expr)?) => {
46        $crate::expand_u32!($bitstream; $($args)+)
47    };
48    ($bitstream:ident, U32($($args:tt)+); UnpackSigned $(, $ctx:expr)?) => {
49        $crate::expand_u32!($bitstream; $($args)+).map(::jxl_bitstream::unpack_signed)
50    };
51    ($bitstream:ident, U64 $(, $ctx:expr)?) => {
52        $bitstream.read_u64()
53    };
54    ($bitstream:ident, U64; UnpackSigned $(, $ctx:expr)?) => {
55        $bitstream.read_u64().map(::jxl_bitstream::unpack_signed_u64)
56    };
57    ($bitstream:ident, F16 $(, $ctx:expr)?) => {
58        $bitstream.read_f16_as_f32()
59    };
60    ($bitstream:ident, Bool $(, $ctx:expr)?) => {
61        $bitstream.read_bool()
62    };
63    ($bitstream:ident, Enum($enumtype:ty) $(, $ctx:expr)?) => {
64        $bitstream.read_enum::<$enumtype>()
65    };
66    ($bitstream:ident, ZeroPadToByte $(, $ctx:expr)?) => {
67        $bitstream.zero_pad_to_byte()
68    };
69    ($bitstream:ident, Bundle($bundle:ty)) => {
70        <$bundle>::parse($bitstream, ())
71    };
72    ($bitstream:ident, Bundle($bundle:ty), $ctx:expr) => {
73        <$bundle>::parse($bitstream, $ctx)
74    };
75    ($bitstream:ident, Vec[$($inner:tt)*]; $count:expr $(, $ctx:expr)?) => {
76        {
77            let count = $count as usize;
78            (0..count)
79                .into_iter()
80                .map(|_| $crate::read_bits!($bitstream, $($inner)* $(, $ctx)?))
81                .collect::<::std::result::Result<Vec<_>, _>>()
82        }
83    };
84    ($bitstream:ident, Array[$($inner:tt)*]; $count:expr $(, $ctx:expr)?) => {
85        (|| -> ::std::result::Result<[_; $count], _> {
86            let mut ret = [Default::default(); $count];
87            for point in &mut ret {
88                *point = match $crate::read_bits!($bitstream, $($inner)* $(, $ctx)?) {
89                    ::std::result::Result::Ok(v) => v,
90                    ::std::result::Result::Err(err) => return ::std::result::Result::Err(err),
91                };
92            }
93            Ok(ret)
94        })()
95    };
96}
97
98#[macro_export]
99#[doc(hidden)]
100macro_rules! make_def {
101    (@ty; $c:literal) => { u32 };
102    (@ty; u($n:literal)) => { u32 };
103    (@ty; u($n:literal); UnpackSigned) => { i32 };
104    (@ty; $c:literal + u($n:literal)) => { u32 };
105    (@ty; $c:literal + u($n:literal); UnpackSigned) => { i32 };
106    (@ty; U32($($args:tt)*)) => { u32 };
107    (@ty; U32($($args:tt)*); UnpackSigned) => { i32 };
108    (@ty; U64) => { u64 };
109    (@ty; U64; UnpackSigned) => { i64 };
110    (@ty; F16) => { f32 };
111    (@ty; Bool) => { bool };
112    (@ty; Enum($enum:ty)) => { $enum };
113    (@ty; Bundle($bundle:ty)) => { $bundle };
114    (@ty; Vec[$($inner:tt)*]; $count:expr) => { Vec<$crate::make_def!(@ty; $($inner)*)> };
115    (@ty; Array[$($inner:tt)*]; $count:expr) => { [$crate::make_def!(@ty; $($inner)*); $count] };
116    ($(#[$attrs:meta])* $v:vis struct $bundle_name:ident {
117        $($(#[$fieldattrs:meta])* $vfield:vis $field:ident: ty($($expr:tt)*) $(ctx($ctx_for_field:expr))? $(cond($cond:expr))? $(default($def_expr:expr))? ,)*
118    }) => {
119        $(#[$attrs])*
120        $v struct $bundle_name {
121            $($(#[$fieldattrs])* $vfield $field: $crate::make_def!(@ty; $($expr)*),)*
122        }
123    };
124}
125
126#[macro_export]
127#[doc(hidden)]
128macro_rules! make_parse {
129    (@parse $bitstream:ident; cond($cond:expr); default($def_expr:expr); ty($($spec:tt)*); ctx($ctx:expr)) => {
130        if $cond {
131            $crate::read_bits!($bitstream, $($spec)*, $ctx)?
132        } else {
133            $def_expr
134        }
135    };
136    (@parse $bitstream:ident; cond($cond:expr); ty($($spec:tt)*); ctx($ctx:expr)) => {
137        if $cond {
138            $crate::read_bits!($bitstream, $($spec)*, $ctx)?
139        } else {
140            <$crate::make_def!(@ty; $($spec)*)>::default_with_context($ctx)
141        }
142    };
143    (@parse $bitstream:ident; $(default($def_expr:expr);)? ty($($spec:tt)*); ctx($ctx:expr)) => {
144        $crate::read_bits!($bitstream, $($spec)*, $ctx)?
145    };
146    (@default($($spec:tt)*); ; $ctx:expr) => {
147        <$crate::make_def!(@ty; $($spec)*)>::default_with_context($ctx)
148    };
149    (@default($($spec:tt)*); $def_expr:expr $(; $ctx:expr)?) => {
150        $def_expr
151    };
152    (@select_ctx; $ctx_id:ident; $ctx:expr) => {
153        $ctx
154    };
155    (@select_ctx; $ctx_id:ident;) => {
156        $ctx_id
157    };
158    (@select_error_ty;) => {
159        ::jxl_bitstream::Error
160    };
161    (@select_error_ty; $err:ty) => {
162        $err
163    };
164    ($bundle_name:ident $(error($err:ty))? {
165        $($(#[$fieldattrs:meta])* $v:vis $field:ident: ty($($expr:tt)*) $(ctx($ctx_for_field:expr))? $(cond($cond:expr))? $(default($def_expr:expr))? ,)*
166    }) => {
167        impl<Ctx: Copy> $crate::Bundle<Ctx> for $bundle_name {
168            type Error = $crate::make_parse!(@select_error_ty; $($err)?);
169
170            #[allow(unused)]
171            fn parse(bitstream: &mut ::jxl_bitstream::Bitstream, ctx: Ctx) -> ::std::result::Result<Self, Self::Error> where Self: Sized {
172                use $crate::{Bundle, BundleDefault};
173                $(
174                    let $field = $crate::make_parse!(
175                        @parse bitstream;
176                        $(cond($cond);)?
177                        $(default($def_expr);)?
178                        ty($($expr)*);
179                        ctx($crate::make_parse!(@select_ctx; ctx; $($ctx_for_field)?))
180                    );
181                )*
182                Ok(Self { $($field,)* })
183            }
184        }
185
186        impl<Ctx: Copy> $crate::BundleDefault<Ctx> for $bundle_name {
187            #[allow(unused)]
188            fn default_with_context(_ctx: Ctx) -> Self where Self: Sized {
189                use $crate::BundleDefault;
190                $(
191                    let $field = $crate::make_parse!(
192                        @default($($expr)*);
193                        $($def_expr)?;
194                        $crate::make_parse!(@select_ctx; _ctx; $($ctx_for_field)?)
195                    );
196                )*
197                Self { $($field,)* }
198            }
199        }
200    };
201    ($bundle_name:ident ctx($ctx_id:ident : $ctx:ty) $(error($err:ty))? {
202        $($(#[$fieldattrs:meta])* $v:vis $field:ident: ty($($expr:tt)*) $(ctx($ctx_for_field:expr))? $(cond($cond:expr))? $(default($def_expr:expr))? ,)*
203    }) => {
204        impl $crate::Bundle<$ctx> for $bundle_name {
205            type Error = $crate::make_parse!(@select_error_ty; $($err)?);
206
207            #[allow(unused)]
208            fn parse(bitstream: &mut ::jxl_bitstream::Bitstream, $ctx_id: $ctx) -> ::std::result::Result<Self, Self::Error> where Self: Sized {
209                use $crate::{Bundle, BundleDefault};
210                $(
211                    let $field = $crate::make_parse!(
212                        @parse bitstream;
213                        $(cond($cond);)?
214                        $(default($def_expr);)?
215                        ty($($expr)*);
216                        ctx($crate::make_parse!(@select_ctx; $ctx_id; $($ctx_for_field)?))
217                    );
218                )*
219                Ok(Self { $($field,)* })
220            }
221        }
222
223        impl $crate::BundleDefault<$ctx> for $bundle_name {
224            #[allow(unused)]
225            fn default_with_context($ctx_id: $ctx) -> Self where Self: Sized {
226                use $crate::BundleDefault;
227                $(
228                    let $field = $crate::make_parse!(
229                        @default($($expr)*);
230                        $($def_expr)?;
231                        $crate::make_parse!(@select_ctx; $ctx_id; $($ctx_for_field)?)
232                    );
233                )*
234                Self { $($field,)* }
235            }
236        }
237    };
238}
239
240#[macro_export]
241macro_rules! define_bundle {
242    (
243        $(
244            $(#[$attrs:meta])*
245            $v:vis struct $bundle_name:ident
246            $(aligned($aligned:literal))?
247            $(ctx($ctx_id:ident : $ctx:ty))?
248            $(error($err:ty))?
249            {
250                $($body:tt)*
251            }
252        )*
253    ) => {
254        $(
255            $crate::make_def!($(#[$attrs])* $v struct $bundle_name { $($body)* });
256            $crate::make_parse!($bundle_name $(aligned($aligned))? $(ctx($ctx_id: $ctx))? $(error($err))? { $($body)* });
257        )*
258    };
259}
260
261pub trait Bundle<Ctx = ()>: Sized {
262    type Error;
263
264    /// Parses a value from the bitstream with the given context.
265    fn parse(bitstream: &mut Bitstream<'_>, ctx: Ctx) -> Result<Self, Self::Error>;
266}
267
268pub trait BundleDefault<Ctx = ()>: Sized {
269    /// Creates a default value with the given context.
270    fn default_with_context(ctx: Ctx) -> Self;
271}
272
273impl<T, Ctx> BundleDefault<Ctx> for T
274where
275    T: Default + Sized,
276{
277    fn default_with_context(_: Ctx) -> Self {
278        Default::default()
279    }
280}
281
282impl<T, Ctx> Bundle<Ctx> for Option<T>
283where
284    T: Bundle<Ctx>,
285{
286    type Error = T::Error;
287
288    fn parse(bitstream: &mut Bitstream, ctx: Ctx) -> Result<Self, Self::Error> {
289        T::parse(bitstream, ctx).map(Some)
290    }
291}
292
293/// Name type which is read by some JPEG XL headers.
294#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
295pub struct Name(String);
296
297impl<Ctx> Bundle<Ctx> for Name {
298    type Error = jxl_bitstream::Error;
299
300    fn parse(bitstream: &mut Bitstream, _: Ctx) -> Result<Self, Self::Error> {
301        let len = read_bits!(bitstream, U32(0, u(4), 16 + u(5), 48 + u(10)))? as usize;
302        let mut data = vec![0u8; len];
303        for b in &mut data {
304            *b = bitstream.read_bits(8)? as u8;
305        }
306        let name = String::from_utf8(data)
307            .map_err(|_| jxl_bitstream::Error::ValidationFailed("non-UTF-8 name"))?;
308        Ok(Self(name))
309    }
310}
311
312impl std::ops::Deref for Name {
313    type Target = String;
314
315    fn deref(&self) -> &Self::Target {
316        &self.0
317    }
318}
319
320impl std::ops::DerefMut for Name {
321    fn deref_mut(&mut self) -> &mut Self::Target {
322        &mut self.0
323    }
324}