1use num_traits::{FromPrimitive, Signed};
2use std::fmt::Debug;
3
4pub trait FftNum: Copy + FromPrimitive + Signed + Sync + Send + Debug + 'static {}
6
7impl<T> FftNum for T where T: Copy + FromPrimitive + Signed + Sync + Send + Debug + 'static {}
8
9#[cold]
12#[inline(never)]
13pub fn fft_error_inplace(
14 expected_len: usize,
15 actual_len: usize,
16 expected_scratch: usize,
17 actual_scratch: usize,
18) {
19 assert!(
20 actual_len >= expected_len,
21 "Provided FFT buffer was too small. Expected len = {}, got len = {}",
22 expected_len,
23 actual_len
24 );
25 assert_eq!(
26 actual_len % expected_len,
27 0,
28 "Input FFT buffer must be a multiple of FFT length. Expected multiple of {}, got len = {}",
29 expected_len,
30 actual_len
31 );
32 assert!(
33 actual_scratch >= expected_scratch,
34 "Not enough scratch space was provided. Expected scratch len >= {}, got scratch len = {}",
35 expected_scratch,
36 actual_scratch
37 );
38}
39
40#[cold]
43#[inline(never)]
44pub fn fft_error_outofplace(
45 expected_len: usize,
46 actual_input: usize,
47 actual_output: usize,
48 expected_scratch: usize,
49 actual_scratch: usize,
50) {
51 assert_eq!(actual_input, actual_output, "Provided FFT input buffer and output buffer must have the same length. Got input.len() = {}, output.len() = {}", actual_input, actual_output);
52 assert!(
53 actual_input >= expected_len,
54 "Provided FFT buffer was too small. Expected len = {}, got len = {}",
55 expected_len,
56 actual_input
57 );
58 assert_eq!(
59 actual_input % expected_len,
60 0,
61 "Input FFT buffer must be a multiple of FFT length. Expected multiple of {}, got len = {}",
62 expected_len,
63 actual_input
64 );
65 assert!(
66 actual_scratch >= expected_scratch,
67 "Not enough scratch space was provided. Expected scratch len >= {}, got scratch len = {}",
68 expected_scratch,
69 actual_scratch
70 );
71}
72
73#[cold]
76#[inline(never)]
77pub fn fft_error_immut(
78 expected_len: usize,
79 actual_input: usize,
80 actual_output: usize,
81 expected_scratch: usize,
82 actual_scratch: usize,
83) {
84 assert_eq!(actual_input, actual_output, "Provided FFT input buffer and output buffer must have the same length. Got input.len() = {}, output.len() = {}", actual_input, actual_output);
85 assert!(
86 actual_input >= expected_len,
87 "Provided FFT buffer was too small. Expected len = {}, got len = {}",
88 expected_len,
89 actual_input
90 );
91 assert_eq!(
92 actual_input % expected_len,
93 0,
94 "Input FFT buffer must be a multiple of FFT length. Expected multiple of {}, got len = {}",
95 expected_len,
96 actual_input
97 );
98 assert!(
99 actual_scratch >= expected_scratch,
100 "Not enough scratch space was provided. Expected scratch len >= {}, got scratch len = {}",
101 expected_scratch,
102 actual_scratch
103 );
104}
105
106macro_rules! boilerplate_fft_oop {
107 ($struct_name:ident, $len_fn:expr) => {
108 impl<T: FftNum> Fft<T> for $struct_name<T> {
109 fn process_immutable_with_scratch(
110 &self,
111 input: &[Complex<T>],
112 output: &mut [Complex<T>],
113 scratch: &mut [Complex<T>],
114 ) {
115 crate::fft_helper::fft_helper_immut(
116 input,
117 output,
118 scratch,
119 self.len(),
120 self.get_immutable_scratch_len(),
121 |in_chunk, out_chunk, scratch| {
122 self.perform_fft_immut(in_chunk, out_chunk, scratch)
123 },
124 );
125 }
126 fn process_outofplace_with_scratch(
127 &self,
128 input: &mut [Complex<T>],
129 output: &mut [Complex<T>],
130 scratch: &mut [Complex<T>],
131 ) {
132 crate::fft_helper::fft_helper_outofplace(
133 input,
134 output,
135 scratch,
136 self.len(),
137 self.get_outofplace_scratch_len(),
138 |in_chunk, out_chunk, scratch| {
139 self.perform_fft_out_of_place(in_chunk, out_chunk, scratch)
140 },
141 );
142 }
143 fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]) {
144 crate::fft_helper::fft_helper_inplace(
145 buffer,
146 scratch,
147 self.len(),
148 self.get_inplace_scratch_len(),
149 |chunk, scratch| {
150 let (self_scratch, inner_scratch) = scratch.split_at_mut(self.len());
151 self.perform_fft_out_of_place(chunk, self_scratch, inner_scratch);
152 chunk.copy_from_slice(self_scratch);
153 },
154 );
155 }
156 #[inline(always)]
157 fn get_inplace_scratch_len(&self) -> usize {
158 self.inplace_scratch_len()
159 }
160 #[inline(always)]
161 fn get_outofplace_scratch_len(&self) -> usize {
162 self.outofplace_scratch_len()
163 }
164 #[inline(always)]
165 fn get_immutable_scratch_len(&self) -> usize {
166 self.immut_scratch_len()
167 }
168 }
169 impl<T> Length for $struct_name<T> {
170 #[inline(always)]
171 fn len(&self) -> usize {
172 $len_fn(self)
173 }
174 }
175 impl<T> Direction for $struct_name<T> {
176 #[inline(always)]
177 fn fft_direction(&self) -> FftDirection {
178 self.direction
179 }
180 }
181 };
182}
183
184macro_rules! boilerplate_fft {
185 ($struct_name:ident, $len_fn:expr, $inplace_scratch_len_fn:expr, $out_of_place_scratch_len_fn:expr, $immut_scratch_len:expr) => {
186 impl<T: FftNum> Fft<T> for $struct_name<T> {
187 fn process_immutable_with_scratch(
188 &self,
189 input: &[Complex<T>],
190 output: &mut [Complex<T>],
191 scratch: &mut [Complex<T>],
192 ) {
193 crate::fft_helper::fft_helper_immut(
194 input,
195 output,
196 scratch,
197 self.len(),
198 self.get_immutable_scratch_len(),
199 |in_chunk, out_chunk, scratch| {
200 self.perform_fft_immut(in_chunk, out_chunk, scratch)
201 },
202 );
203 }
204
205 fn process_outofplace_with_scratch(
206 &self,
207 input: &mut [Complex<T>],
208 output: &mut [Complex<T>],
209 scratch: &mut [Complex<T>],
210 ) {
211 crate::fft_helper::fft_helper_outofplace(
212 input,
213 output,
214 scratch,
215 self.len(),
216 self.get_outofplace_scratch_len(),
217 |in_chunk, out_chunk, scratch| {
218 self.perform_fft_out_of_place(in_chunk, out_chunk, scratch)
219 },
220 );
221 }
222 fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]) {
223 crate::fft_helper::fft_helper_inplace(
224 buffer,
225 scratch,
226 self.len(),
227 self.get_inplace_scratch_len(),
228 |chunk, scratch| {
229 self.perform_fft_inplace(chunk, scratch);
230 },
231 );
232 }
233 #[inline(always)]
234 fn get_inplace_scratch_len(&self) -> usize {
235 $inplace_scratch_len_fn(self)
236 }
237 #[inline(always)]
238 fn get_outofplace_scratch_len(&self) -> usize {
239 $out_of_place_scratch_len_fn(self)
240 }
241 #[inline(always)]
242 fn get_immutable_scratch_len(&self) -> usize {
243 $immut_scratch_len(self)
244 }
245 }
246 impl<T: FftNum> Length for $struct_name<T> {
247 #[inline(always)]
248 fn len(&self) -> usize {
249 $len_fn(self)
250 }
251 }
252 impl<T: FftNum> Direction for $struct_name<T> {
253 #[inline(always)]
254 fn fft_direction(&self) -> FftDirection {
255 self.direction
256 }
257 }
258 };
259}
260
261#[non_exhaustive]
262#[repr(u8)]
263#[derive(Copy, Clone, Debug, PartialEq)]
264pub(crate) enum RadixFactor {
265 Factor2,
266 Factor3,
267 Factor4,
268 Factor5,
269 Factor6,
270 Factor7,
271}
272impl RadixFactor {
273 pub const fn radix(&self) -> usize {
274 match self {
276 RadixFactor::Factor2 => 2,
277 RadixFactor::Factor3 => 3,
278 RadixFactor::Factor4 => 4,
279 RadixFactor::Factor5 => 5,
280 RadixFactor::Factor6 => 6,
281 RadixFactor::Factor7 => 7,
282 }
283 }
284}