1use std::{marker::PhantomData, ops::BitXor};
4
5use crate::{UnderlierType, WithUnderlier, underlier::Divisible, util::expand_subset_xors};
6
7pub trait Transformation<Input, Output>: Sync {
9 fn transform(&self, data: &Input) -> Output;
10}
11
12const LOG_BITS_PER_BYTE: usize = 3;
13const BITS_PER_BYTE: usize = 1 << LOG_BITS_PER_BYTE;
14
15#[derive(Debug)]
22pub struct BytewiseLookupTransformation<UIn, UOut> {
23 lookup: Vec<[UOut; 1 << BITS_PER_BYTE]>,
24 _uin_marker: PhantomData<UIn>,
25}
26
27impl<UIn, UOut> BytewiseLookupTransformation<UIn, UOut>
28where
29 UIn: UnderlierType + Divisible<u8>,
30 UOut: UnderlierType,
31{
32 pub fn new(cols: &[UOut]) -> Self {
33 assert!(LOG_BITS_PER_BYTE <= UIn::LOG_BITS);
34 assert_eq!(cols.len(), UIn::BITS);
35
36 let lookup = cols
37 .chunks(BITS_PER_BYTE)
38 .map(|cols| {
39 let cols: [_; BITS_PER_BYTE] = cols.try_into().expect(
40 "chunk size is BITS_PER_BYTE; \
41 cols.len() is a multiple of BITS_PER_BYTE",
42 );
43 expand_subset_xors(cols)
44 })
45 .collect();
46
47 Self {
48 lookup,
49 _uin_marker: PhantomData,
50 }
51 }
52}
53
54impl<UIn, UOut> Transformation<UIn, UOut> for BytewiseLookupTransformation<UIn, UOut>
55where
56 UIn: UnderlierType + Divisible<u8>,
57 UOut: UnderlierType,
58{
59 #[inline]
60 fn transform(&self, data: &UIn) -> UOut {
61 Divisible::<u8>::ref_iter(data)
62 .enumerate()
63 .take(1 << (UIn::LOG_BITS - LOG_BITS_PER_BYTE))
64 .map(|(i, byte)| {
65 let lookup = unsafe { self.lookup.get_unchecked(i) };
69 lookup[byte as usize]
70 })
71 .reduce(BitXor::bitxor)
72 .unwrap_or(UOut::ZERO)
73 }
74}
75
76#[derive(Debug)]
78pub struct BytewiseLookupTransformationFactory;
79
80pub trait LinearTransformationFactory<Input, Output> {
82 type Transform: Transformation<Input, Output>;
83
84 fn create(&self, cols: &[Output]) -> Self::Transform;
85}
86
87impl<UIn, UOut> LinearTransformationFactory<UIn, UOut> for BytewiseLookupTransformationFactory
88where
89 UIn: UnderlierType + Divisible<u8>,
90 UOut: UnderlierType,
91{
92 type Transform = BytewiseLookupTransformation<UIn, UOut>;
93
94 fn create(&self, cols: &[UOut]) -> Self::Transform {
95 BytewiseLookupTransformation::new(cols)
96 }
97}
98
99#[derive(Debug)]
101pub struct OutputWrappingTransformation<Inner, Input, Output> {
102 inner: Inner,
103 _marker: PhantomData<(Input, Output)>,
104}
105
106impl<Inner, Input, Output> Transformation<Input, Output>
107 for OutputWrappingTransformation<Inner, Input, Output>
108where
109 Inner: Transformation<Input, Output::Underlier>,
110 Input: Sync,
111 Output: WithUnderlier,
112{
113 #[inline]
114 fn transform(&self, data: &Input) -> Output {
115 Output::from_underlier(self.inner.transform(data))
116 }
117}
118
119#[derive(Debug)]
121pub struct OutputWrappingTransformationFactory<Inner, Input, Output> {
122 inner: Inner,
123 _marker: PhantomData<(Input, Output)>,
124}
125
126impl<Inner, Input, Output> OutputWrappingTransformationFactory<Inner, Input, Output>
127where
128 Inner: LinearTransformationFactory<Input, Output::Underlier>,
129 Input: Sync,
130 Output: WithUnderlier,
131{
132 pub const fn new(inner: Inner) -> Self {
133 Self {
134 inner,
135 _marker: PhantomData,
136 }
137 }
138}
139
140impl<Inner, Input, Output> LinearTransformationFactory<Input, Output>
141 for OutputWrappingTransformationFactory<Inner, Input, Output>
142where
143 Inner: LinearTransformationFactory<Input, Output::Underlier>,
144 Input: Sync,
145 Output: WithUnderlier,
146{
147 type Transform = OutputWrappingTransformation<Inner::Transform, Input, Output>;
148
149 #[inline]
150 fn create(&self, cols: &[Output]) -> Self::Transform {
151 OutputWrappingTransformation {
152 inner: self.inner.create(Output::to_underliers_ref(cols)),
153 _marker: PhantomData,
154 }
155 }
156}
157
158#[derive(Debug)]
160pub struct InputWrappingTransformation<Inner, Input, Output> {
161 inner: Inner,
162 _marker: PhantomData<(Input, Output)>,
163}
164
165impl<Inner, Input, Output> Transformation<Input, Output>
166 for InputWrappingTransformation<Inner, Input, Output>
167where
168 Inner: Transformation<Input::Underlier, Output>,
169 Input: WithUnderlier,
170 Output: Sync,
171{
172 #[inline]
173 fn transform(&self, data: &Input) -> Output {
174 self.inner.transform(&data.to_underlier())
175 }
176}
177
178#[derive(Debug)]
180pub struct InputWrappingTransformationFactory<Inner, Input, Output> {
181 inner: Inner,
182 _marker: PhantomData<(Input, Output)>,
183}
184
185impl<Inner, Input, Output> InputWrappingTransformationFactory<Inner, Input, Output>
186where
187 Inner: LinearTransformationFactory<Input::Underlier, Output>,
188 Input: WithUnderlier,
189 Output: Sync,
190{
191 pub const fn new(inner: Inner) -> Self {
192 Self {
193 inner,
194 _marker: PhantomData,
195 }
196 }
197}
198
199impl<Inner, Input, Output> LinearTransformationFactory<Input, Output>
200 for InputWrappingTransformationFactory<Inner, Input, Output>
201where
202 Inner: LinearTransformationFactory<Input::Underlier, Output>,
203 Input: WithUnderlier,
204 Output: Sync,
205{
206 type Transform = InputWrappingTransformation<Inner::Transform, Input, Output>;
207
208 #[inline]
209 fn create(&self, cols: &[Output]) -> Self::Transform {
210 InputWrappingTransformation {
211 inner: self.inner.create(cols),
212 _marker: PhantomData,
213 }
214 }
215}
216
217pub type WrappingTransformation<Inner, Input, Output> = OutputWrappingTransformation<
219 InputWrappingTransformation<Inner, Input, <Output as WithUnderlier>::Underlier>,
220 Input,
221 Output,
222>;