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