Skip to main content

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