jxl_oxide_common/
lib.rs

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