jxl_modular/
sample.rs

1use jxl_bitstream::unpack_signed;
2use jxl_grid::{AlignedGrid, MutableSubgrid};
3
4pub trait Sealed: Copy + Default + Send + Sync {
5    fn try_as_mutable_subgrid_i32<'a, 'g>(
6        grid: &'a mut MutableSubgrid<'g, Self>,
7    ) -> Option<&'a mut MutableSubgrid<'g, i32>>;
8    fn try_as_mutable_subgrid_i16<'a, 'g>(
9        grid: &'a mut MutableSubgrid<'g, Self>,
10    ) -> Option<&'a mut MutableSubgrid<'g, i16>>;
11    fn try_into_grid_i32(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i32>, AlignedGrid<Self>>;
12    fn try_into_grid_i16(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i16>, AlignedGrid<Self>>;
13
14    fn unpack_signed_u32(value: u32) -> Self;
15
16    /// Performs wrapping addition.
17    fn add(self, rhs: Self) -> Self;
18
19    /// Performs wrapping multiplication followed by wrapping addition.
20    fn wrapping_muladd_i32(self, mul: i32, add: i32) -> Self;
21
22    /// Computes clamped gradient, which is `(n + w - nw).clamp(w.min(n), w.max(n))`.
23    fn grad_clamped(n: Self, w: Self, nw: Self) -> Self;
24}
25
26/// Type of Modular image samples.
27///
28/// Currently `i32` and `i16` implements `Sample`.
29pub trait Sample: Copy + Default + Send + Sync + Sealed + 'static {
30    fn from_i32(value: i32) -> Self;
31    fn from_u32(value: u32) -> Self;
32
33    fn to_i32(self) -> i32;
34    fn to_i64(self) -> i64;
35    fn to_f32(self) -> f32;
36}
37
38impl Sample for i32 {
39    #[inline]
40    fn from_i32(value: i32) -> Self {
41        value
42    }
43
44    #[inline]
45    fn from_u32(value: u32) -> Self {
46        value as i32
47    }
48
49    #[inline]
50    fn to_i32(self) -> i32 {
51        self
52    }
53
54    #[inline]
55    fn to_i64(self) -> i64 {
56        self as i64
57    }
58
59    #[inline]
60    fn to_f32(self) -> f32 {
61        self as f32
62    }
63}
64
65impl Sample for i16 {
66    #[inline]
67    fn from_i32(value: i32) -> Self {
68        value as i16
69    }
70
71    #[inline]
72    fn from_u32(value: u32) -> Self {
73        value as i16
74    }
75
76    #[inline]
77    fn to_i32(self) -> i32 {
78        self as i32
79    }
80
81    #[inline]
82    fn to_i64(self) -> i64 {
83        self as i64
84    }
85
86    #[inline]
87    fn to_f32(self) -> f32 {
88        self as f32
89    }
90}
91
92impl Sealed for i32 {
93    fn try_as_mutable_subgrid_i32<'a, 'g>(
94        grid: &'a mut MutableSubgrid<'g, i32>,
95    ) -> Option<&'a mut MutableSubgrid<'g, i32>> {
96        Some(grid)
97    }
98
99    fn try_as_mutable_subgrid_i16<'a, 'g>(
100        _: &'a mut MutableSubgrid<'g, i32>,
101    ) -> Option<&'a mut MutableSubgrid<'g, i16>> {
102        None
103    }
104
105    fn try_into_grid_i32(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i32>, AlignedGrid<Self>> {
106        Ok(grid)
107    }
108
109    fn try_into_grid_i16(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i16>, AlignedGrid<Self>> {
110        Err(grid)
111    }
112
113    #[inline]
114    fn unpack_signed_u32(value: u32) -> Self {
115        unpack_signed(value)
116    }
117
118    #[inline]
119    fn add(self, rhs: i32) -> i32 {
120        self.wrapping_add(rhs)
121    }
122
123    #[inline]
124    fn wrapping_muladd_i32(self, mul: i32, add: i32) -> i32 {
125        self.wrapping_mul(mul).wrapping_add(add)
126    }
127
128    #[inline]
129    fn grad_clamped(n: i32, w: i32, nw: i32) -> i32 {
130        let (n, w) = if w > n {
131            (w as i64, n as i64)
132        } else {
133            (n as i64, w as i64)
134        };
135        (w + n - nw as i64).clamp(w, n) as i32
136    }
137}
138
139impl Sealed for i16 {
140    fn try_as_mutable_subgrid_i32<'a, 'g>(
141        _: &'a mut MutableSubgrid<'g, i16>,
142    ) -> Option<&'a mut MutableSubgrid<'g, i32>> {
143        None
144    }
145
146    fn try_as_mutable_subgrid_i16<'a, 'g>(
147        grid: &'a mut MutableSubgrid<'g, i16>,
148    ) -> Option<&'a mut MutableSubgrid<'g, i16>> {
149        Some(grid)
150    }
151
152    fn try_into_grid_i32(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i32>, AlignedGrid<Self>> {
153        Err(grid)
154    }
155
156    fn try_into_grid_i16(grid: AlignedGrid<Self>) -> Result<AlignedGrid<i16>, AlignedGrid<Self>> {
157        Ok(grid)
158    }
159
160    #[inline]
161    fn unpack_signed_u32(value: u32) -> Self {
162        let bit = (value & 1) as u16;
163        let base = (value >> 1) as u16;
164        let flip = 0u16.wrapping_sub(bit);
165        (base ^ flip) as i16
166    }
167
168    #[inline]
169    fn add(self, rhs: i16) -> i16 {
170        self.wrapping_add(rhs)
171    }
172
173    #[inline]
174    fn wrapping_muladd_i32(self, mul: i32, add: i32) -> i16 {
175        self.wrapping_mul(mul as i16).wrapping_add(add as i16)
176    }
177
178    #[inline]
179    fn grad_clamped(n: i16, w: i16, nw: i16) -> i16 {
180        let (n, w) = if w > n {
181            (w as i32, n as i32)
182        } else {
183            (n as i32, w as i32)
184        };
185        (w + n - nw as i32).clamp(w, n) as i16
186    }
187}