rustfft/
lib.rs

1//! RustFFT is a high-performance FFT library written in pure Rust.
2//!
3//! On X86_64, RustFFT supports the AVX instruction set for increased performance. No special code is needed to activate AVX:
4//! Simply plan a FFT using the FftPlanner on a machine that supports the `avx` and `fma` CPU features, and RustFFT
5//! will automatically switch to faster AVX-accelerated algorithms.
6//!
7//! For machines that do not have AVX, RustFFT also supports the SSE4.1 instruction set.
8//! As for AVX, this is enabled automatically when using the FftPlanner.
9//!
10//! Additionally, there is automatic support for the Neon instruction set on AArch64,
11//! and support for WASM SIMD when compiling for WASM targets.
12//!
13//! ### Usage
14//!
15//! The recommended way to use RustFFT is to create a [`FftPlanner`] instance and then call its
16//! [`plan_fft`](crate::FftPlanner::plan_fft) method. This method will automatically choose which FFT algorithms are best
17//! for a given size and initialize the required buffers and precomputed data.
18//!
19//! ```
20//! // Perform a forward FFT of size 1234
21//! use rustfft::{FftPlanner, num_complex::Complex};
22//!
23//! let mut planner = FftPlanner::new();
24//! let fft = planner.plan_fft_forward(1234);
25//!
26//! let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234];
27//! fft.process(&mut buffer);
28//! ```
29//! The planner returns trait objects of the [`Fft`] trait, allowing for FFT sizes that aren't known
30//! until runtime.
31//!
32//! RustFFT also exposes individual FFT algorithms. For example, if you know beforehand that you need a power-of-two FFT, you can
33//! avoid the overhead of the planner and trait object by directly creating instances of the [`Radix4`](crate::algorithm::Radix4) algorithm:
34//!
35//! ```
36//! // Computes a forward FFT of size 4096
37//! use rustfft::{Fft, FftDirection, num_complex::Complex, algorithm::Radix4};
38//!
39//! let fft = Radix4::new(4096, FftDirection::Forward);
40//!
41//! let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 4096];
42//! fft.process(&mut buffer);
43//! ```
44//!
45//! For the vast majority of situations, simply using the [`FftPlanner`] will be enough, but
46//! advanced users may have better insight than the planner into which algorithms are best for a specific size. See the
47//! [`algorithm`] module for a complete list of scalar algorithms implemented by RustFFT.
48//!
49//! Users should beware, however, that bypassing the planner will disable all AVX, SSE, Neon, and WASM SIMD optimizations.
50//!
51//! ### Feature Flags
52//!
53//! * `avx` (Enabled by default)
54//!
55//!     On x86_64, the `avx` feature enables compilation of AVX-accelerated code. Enabling it greatly improves performance if the
56//!     client CPU supports AVX and FMA, while disabling it reduces compile time and binary size.
57//!
58//!     On every platform besides x86_64, this feature does nothing, and RustFFT will behave like it's not set.
59//! * `sse` (Enabled by default)
60//!
61//!     On x86_64, the `sse` feature enables compilation of SSE4.1-accelerated code. Enabling it improves performance
62//!     if the client CPU supports SSE4.1, while disabling it reduces compile time and binary size. If AVX is also
63//!     supported and its feature flag is enabled, RustFFT will use AVX instead of SSE4.1.
64//!
65//!     On every platform besides x86_64, this feature does nothing, and RustFFT will behave like it's not set.
66//! * `neon` (Enabled by default)
67//!
68//!     On AArch64 (64-bit ARM) the `neon` feature enables compilation of Neon-accelerated code. Enabling it improves
69//!     performance, while disabling it reduces compile time and binary size.
70//!
71//!     On every platform besides AArch64, this feature does nothing, and RustFFT will behave like it's not set.
72//! * `wasm_simd` (Disabled by default)
73//!
74//!     On the WASM platform, this feature enables compilation of WASM SIMD accelerated code.
75//!
76//!     To execute binaries compiled with `wasm_simd`, you need a [target browser or runtime which supports `fixed-width SIMD`](https://webassembly.org/roadmap/).
77//!     If you run your SIMD accelerated code on an unsupported platform, WebAssembly will specify a [trap](https://webassembly.github.io/spec/core/intro/overview.html#trap) leading to immediate execution cancelation.
78//!
79//!     On every platform besides WASM, this feature does nothing and RustFFT will behave like it is not set.
80//!
81//! ### Normalization
82//!
83//! RustFFT does not normalize outputs. Callers must manually normalize the results by scaling each element by
84//! `1/len().sqrt()`. Multiple normalization steps can be merged into one via pairwise multiplication, so when
85//! doing a forward FFT followed by an inverse callers can normalize once by scaling each element by `1/len()`
86//!
87//! ### Output Order
88//!
89//! Elements in the output are ordered by ascending frequency, with the first element corresponding to frequency 0.
90//!
91//! ### AVX Performance Tips
92//!
93//! In any FFT computation, the time required to compute a FFT of size N relies heavily on the [prime factorization](https://en.wikipedia.org/wiki/Integer_factorization) of N.
94//! If N's prime factors are all very small, computing a FFT of size N will be fast, and it'll be slow if N has large prime
95//! factors, or if N is a prime number.
96//!
97//! In most FFT libraries (Including RustFFT when using non-AVX code), power-of-two FFT sizes are the fastest, and users see a steep
98//! falloff in performance when using non-power-of-two sizes. Thankfully, RustFFT using AVX acceleration is not quite as restrictive:
99//!
100//! - Any FFT whose size is of the form `2^n * 3^m` can be considered the "fastest" in RustFFT.
101//! - Any FFT whose prime factors are all 11 or smaller will also be very fast, but the fewer the factors of 2 and 3 the slower it will be.
102//!     For example, computing a FFT of size 13552 `(2^4*7*11*11)` is takes 12% longer to compute than 13824 `(2^9 * 3^3)`,
103//!     and computing a FFT of size 2541 `(3*7*11*11)` takes 65% longer to compute than 2592 `(2^5 * 3^4)`
104//! - Any other FFT size will be noticeably slower. A considerable amount of effort has been put into making these FFT sizes as fast as
105//!     they can be, but some FFT sizes just take more work than others. For example, computing a FFT of size 5183 `(71 * 73)` takes about
106//!     5x longer than computing a FFT of size 5184 `(2^6 * 3^4)`.
107//!
108//! In most cases, even prime-sized FFTs will be fast enough for your application. In the example of 5183 above, even that "slow" FFT
109//! only takes a few tens of microseconds to compute.
110//!
111//! Some applications of the FFT allow for choosing an arbitrary FFT size (In many applications the size is pre-determined by whatever you're computing).
112//! If your application supports choosing your own size, our advice is still to start by trying the size that's most convenient to your application.
113//! If that's too slow, see if you can find a nearby size whose prime factors are all 11 or smaller, and you can expect a 2x-5x speedup.
114//! If that's still too slow, find a nearby size whose prime factors are all 2 or 3, and you can expect a 1.1x-1.5x speedup.
115
116use std::fmt::Display;
117
118pub use num_complex;
119pub use num_traits;
120
121#[macro_use]
122mod common;
123
124/// Individual FFT algorithms
125pub mod algorithm;
126mod array_utils;
127mod fft_cache;
128mod fft_helper;
129mod math_utils;
130mod plan;
131mod twiddles;
132
133use num_complex::Complex;
134use num_traits::Zero;
135
136pub use crate::common::FftNum;
137pub use crate::plan::{FftPlanner, FftPlannerScalar};
138
139/// A trait that allows FFT algorithms to report their expected input/output size
140pub trait Length {
141    /// The FFT size that this algorithm can process
142    fn len(&self) -> usize;
143}
144
145/// Represents a FFT direction, IE a forward FFT or an inverse FFT
146#[derive(Copy, Clone, PartialEq, Eq, Debug)]
147pub enum FftDirection {
148    Forward,
149    Inverse,
150}
151impl FftDirection {
152    /// Returns the opposite direction of `self`.
153    ///
154    ///  - If `self` is `FftDirection::Forward`, returns `FftDirection::Inverse`
155    ///  - If `self` is `FftDirection::Inverse`, returns `FftDirection::Forward`
156    #[inline]
157    pub fn opposite_direction(&self) -> FftDirection {
158        match self {
159            Self::Forward => Self::Inverse,
160            Self::Inverse => Self::Forward,
161        }
162    }
163}
164impl Display for FftDirection {
165    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
166        match self {
167            Self::Forward => f.write_str("Forward"),
168            Self::Inverse => f.write_str("Inverse"),
169        }
170    }
171}
172
173/// A trait that allows FFT algorithms to report whether they compute forward FFTs or inverse FFTs
174pub trait Direction {
175    /// Returns FftDirection::Forward if this instance computes forward FFTs, or FftDirection::Inverse for inverse FFTs
176    fn fft_direction(&self) -> FftDirection;
177}
178
179/// Trait for algorithms that compute FFTs.
180///
181/// This trait has a few methods for computing FFTs. Its most conveinent method is [`process(slice)`](crate::Fft::process).
182/// It takes in a slice of `Complex<T>` and computes a FFT on that slice, in-place. It may copy the data over to internal scratch buffers
183/// if that speeds up the computation, but the output will always end up in the same slice as the input.
184pub trait Fft<T: FftNum>: Length + Direction + Sync + Send {
185    /// Computes a FFT in-place.
186    ///
187    /// Convenience method that allocates a `Vec` with the required scratch space and calls `self.process_with_scratch`.
188    /// If you want to re-use that allocation across multiple FFT computations, consider calling `process_with_scratch` instead.
189    ///
190    /// # Panics
191    ///
192    /// This method panics if:
193    /// - `buffer.len() % self.len() > 0`
194    /// - `buffer.len() < self.len()`
195    fn process(&self, buffer: &mut [Complex<T>]) {
196        let mut scratch = vec![Complex::zero(); self.get_inplace_scratch_len()];
197        self.process_with_scratch(buffer, &mut scratch);
198    }
199
200    /// Divides `buffer` into chunks of size `self.len()`, and computes a FFT on each chunk.
201    ///
202    /// Uses the `scratch` buffer as scratch space, so the contents of `scratch` should be considered garbage
203    /// after calling.
204    ///
205    /// # Panics
206    ///
207    /// This method panics if:
208    /// - `buffer.len() % self.len() > 0`
209    /// - `buffer.len() < self.len()`
210    /// - `scratch.len() < self.get_inplace_scratch_len()`
211    fn process_with_scratch(&self, buffer: &mut [Complex<T>], scratch: &mut [Complex<T>]);
212
213    /// Divides `input` and `output` into chunks of size `self.len()`, and computes a FFT on each chunk.
214    ///
215    /// This method uses both the `input` buffer and `scratch` buffer as scratch space, so the contents of both should be
216    /// considered garbage after calling.
217    ///
218    /// This is a more niche way of computing a FFT. It's useful to avoid a `copy_from_slice()` if you need the output
219    /// in a different buffer than the input for some reason. This happens frequently in RustFFT internals, but is probably
220    /// less common among RustFFT users.
221    ///
222    /// For many FFT sizes, `self.get_outofplace_scratch_len()` returns 0
223    ///
224    /// # Panics
225    ///
226    /// This method panics if:
227    /// - `output.len() != input.len()`
228    /// - `input.len() % self.len() > 0`
229    /// - `input.len() < self.len()`
230    /// - `scratch.len() < self.get_outofplace_scratch_len()`
231    fn process_outofplace_with_scratch(
232        &self,
233        input: &mut [Complex<T>],
234        output: &mut [Complex<T>],
235        scratch: &mut [Complex<T>],
236    );
237
238    /// Divides `input` and `output` into chunks of `self.len()`, and computes a FFT on each chunk while
239    /// keeping `input` untouched.
240    ///
241    /// This method uses the `scratch` buffer as scratch space, so the contents should be considered garbage after calling.
242    ///
243    /// # Panics
244    ///
245    /// This method panics if:
246    /// - `output.len() ! input.len()`
247    /// - `input.len() % self.len() > 0`
248    /// - `input.len() < self.len()`
249    /// - `scratch.len() < get_immutable_scratch_len()`
250    fn process_immutable_with_scratch(
251        &self,
252        input: &[Complex<T>],
253        output: &mut [Complex<T>],
254        scratch: &mut [Complex<T>],
255    );
256
257    /// Returns the size of the scratch buffer required by `process_with_scratch`
258    ///
259    /// For most FFT sizes, this method will return `self.len()`. For a few small sizes it will return 0, and for some special FFT sizes
260    /// (Sizes that require the use of Bluestein's Algorithm), this may return a scratch size larger than `self.len()`.
261    /// The returned value may change from one version of RustFFT to the next.
262    fn get_inplace_scratch_len(&self) -> usize;
263
264    /// Returns the size of the scratch buffer required by `process_outofplace_with_scratch`
265    ///
266    /// For most FFT sizes, this method will return 0. For some special FFT sizes
267    /// (Sizes that require the use of Bluestein's Algorithm), this may return a scratch size larger than `self.len()`.
268    /// The returned value may change from one version of RustFFT to the next.
269    fn get_outofplace_scratch_len(&self) -> usize;
270
271    /// Returns the size of the scratch buffer required by `process_immutable_with_scratch`
272    ///
273    /// For most FFT sizes, this method will return something between self.len() and self.len() * 2.
274    /// For a few small sizes it will return 0, and for some special FFT sizes
275    /// (Sizes that require the use of Bluestein's Algorithm), this may return a scratch size larger than `self.len()`.
276    /// The returned value may change from one version of RustFFT to the next.
277    fn get_immutable_scratch_len(&self) -> usize;
278}
279
280// Algorithms implemented to use AVX instructions. Only compiled on x86_64, and only compiled if the "avx" feature flag is set.
281#[cfg(all(target_arch = "x86_64", feature = "avx"))]
282mod avx;
283
284// If we're not on x86_64, or if the "avx" feature was disabled, keep a stub implementation around that has the same API, but does nothing
285// That way, users can write code using the AVX planner and compile it on any platform
286#[cfg(not(all(target_arch = "x86_64", feature = "avx")))]
287mod avx {
288    pub mod avx_planner {
289        use crate::{Fft, FftDirection, FftNum};
290        use std::sync::Arc;
291
292        /// The AVX FFT planner creates new FFT algorithm instances which take advantage of the AVX instruction set.
293        ///
294        /// Creating an instance of `FftPlannerAvx` requires the `avx` and `fma` instructions to be available on the current machine, and it requires RustFFT's
295        ///  `avx` feature flag to be set. A few algorithms will use `avx2` if it's available, but it isn't required.
296        ///
297        /// For the time being, AVX acceleration is black box, and AVX accelerated algorithms are not available without a planner. This may change in the future.
298        ///
299        /// ~~~
300        /// // Perform a forward Fft of size 1234, accelerated by AVX
301        /// use std::sync::Arc;
302        /// use rustfft::{FftPlannerAvx, num_complex::Complex};
303        ///
304        /// // If FftPlannerAvx::new() returns Ok(), we'll know AVX algorithms are available
305        /// // on this machine, and that RustFFT was compiled with the `avx` feature flag
306        /// if let Ok(mut planner) = FftPlannerAvx::new() {
307        ///     let fft = planner.plan_fft_forward(1234);
308        ///
309        ///     let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234];
310        ///     fft.process(&mut buffer);
311        ///
312        ///     // The FFT instance returned by the planner has the type `Arc<dyn Fft<T>>`,
313        ///     // where T is the numeric type, ie f32 or f64, so it's cheap to clone
314        ///     let fft_clone = Arc::clone(&fft);
315        /// }
316        /// ~~~
317        ///
318        /// If you plan on creating multiple FFT instances, it is recommended to reuse the same planner for all of them. This
319        /// is because the planner re-uses internal data across FFT instances wherever possible, saving memory and reducing
320        /// setup time. (FFT instances created with one planner will never re-use data and buffers with FFT instances created
321        /// by a different planner)
322        ///
323        /// Each FFT instance owns [`Arc`s](std::sync::Arc) to its internal data, rather than borrowing it from the planner, so it's perfectly
324        /// safe to drop the planner after creating Fft instances.
325        pub struct FftPlannerAvx<T: FftNum> {
326            _phantom: std::marker::PhantomData<T>,
327        }
328        impl<T: FftNum> FftPlannerAvx<T> {
329            /// Constructs a new `FftPlannerAvx` instance.
330            ///
331            /// Returns `Ok(planner_instance)` if this machine has the required instruction sets and the `avx` feature flag is set.
332            /// Returns `Err(())` if some instruction sets are missing, or if the `avx` feature flag is not set.
333            pub fn new() -> Result<Self, ()> {
334                Err(())
335            }
336            /// Returns a `Fft` instance which uses AVX instructions to compute FFTs of size `len`.
337            ///
338            /// If the provided `direction` is `FftDirection::Forward`, the returned instance will compute forward FFTs. If it's `FftDirection::Inverse`, it will compute inverse FFTs.
339            ///
340            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
341            pub fn plan_fft(&mut self, _len: usize, _direction: FftDirection) -> Arc<dyn Fft<T>> {
342                unreachable!()
343            }
344            /// Returns a `Fft` instance which uses AVX instructions to compute forward FFTs of size `len`.
345            ///
346            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
347            pub fn plan_fft_forward(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
348                unreachable!()
349            }
350            /// Returns a `Fft` instance which uses AVX instructions to compute inverse FFTs of size `len.
351            ///
352            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
353            pub fn plan_fft_inverse(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
354                unreachable!()
355            }
356        }
357    }
358}
359
360pub use self::avx::avx_planner::FftPlannerAvx;
361
362// Algorithms implemented to use SSE4.1 instructions. Only compiled on x86_64, and only compiled if the "sse" feature flag is set.
363#[cfg(all(target_arch = "x86_64", feature = "sse"))]
364mod sse;
365
366// If we're not on x86_64, or if the "sse" feature was disabled, keep a stub implementation around that has the same API, but does nothing
367// That way, users can write code using the SSE planner and compile it on any platform
368#[cfg(not(all(target_arch = "x86_64", feature = "sse")))]
369mod sse {
370    pub mod sse_planner {
371        use crate::{Fft, FftDirection, FftNum};
372        use std::sync::Arc;
373
374        /// The SSE FFT planner creates new FFT algorithm instances using a mix of scalar and SSE accelerated algorithms.
375        /// It requires at least SSE4.1, which is available on all reasonably recent x86_64 cpus.
376        ///
377        /// RustFFT has several FFT algorithms available. For a given FFT size, the `FftPlannerSse` decides which of the
378        /// available FFT algorithms to use and then initializes them.
379        ///
380        /// ~~~
381        /// // Perform a forward Fft of size 1234
382        /// use std::sync::Arc;
383        /// use rustfft::{FftPlannerSse, num_complex::Complex};
384        ///
385        /// if let Ok(mut planner) = FftPlannerSse::new() {
386        ///   let fft = planner.plan_fft_forward(1234);
387        ///
388        ///   let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234];
389        ///   fft.process(&mut buffer);
390        ///
391        ///   // The FFT instance returned by the planner has the type `Arc<dyn Fft<T>>`,
392        ///   // where T is the numeric type, ie f32 or f64, so it's cheap to clone
393        ///   let fft_clone = Arc::clone(&fft);
394        /// }
395        /// ~~~
396        ///
397        /// If you plan on creating multiple FFT instances, it is recommended to reuse the same planner for all of them. This
398        /// is because the planner re-uses internal data across FFT instances wherever possible, saving memory and reducing
399        /// setup time. (FFT instances created with one planner will never re-use data and buffers with FFT instances created
400        /// by a different planner)
401        ///
402        /// Each FFT instance owns [`Arc`s](std::sync::Arc) to its internal data, rather than borrowing it from the planner, so it's perfectly
403        /// safe to drop the planner after creating Fft instances.
404        pub struct FftPlannerSse<T: FftNum> {
405            _phantom: std::marker::PhantomData<T>,
406        }
407        impl<T: FftNum> FftPlannerSse<T> {
408            /// Creates a new `FftPlannerSse` instance.
409            ///
410            /// Returns `Ok(planner_instance)` if this machine has the required instruction sets.
411            /// Returns `Err(())` if some instruction sets are missing.
412            pub fn new() -> Result<Self, ()> {
413                Err(())
414            }
415            /// Returns a `Fft` instance which uses SSE4.1 instructions to compute FFTs of size `len`.
416            ///
417            /// If the provided `direction` is `FftDirection::Forward`, the returned instance will compute forward FFTs. If it's `FftDirection::Inverse`, it will compute inverse FFTs.
418            ///
419            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
420            pub fn plan_fft(&mut self, _len: usize, _direction: FftDirection) -> Arc<dyn Fft<T>> {
421                unreachable!()
422            }
423            /// Returns a `Fft` instance which uses SSE4.1 instructions to compute forward FFTs of size `len`.
424            ///
425            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
426            pub fn plan_fft_forward(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
427                unreachable!()
428            }
429            /// Returns a `Fft` instance which uses SSE4.1 instructions to compute inverse FFTs of size `len.
430            ///
431            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
432            pub fn plan_fft_inverse(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
433                unreachable!()
434            }
435        }
436    }
437}
438
439pub use self::sse::sse_planner::FftPlannerSse;
440
441// Algorithms implemented to use Neon instructions. Only compiled on AArch64, and only compiled if the "neon" feature flag is set.
442#[cfg(all(target_arch = "aarch64", feature = "neon"))]
443mod neon;
444
445// If we're not on AArch64, or if the "neon" feature was disabled, keep a stub implementation around that has the same API, but does nothing
446// That way, users can write code using the Neon planner and compile it on any platform
447#[cfg(not(all(target_arch = "aarch64", feature = "neon")))]
448mod neon {
449    pub mod neon_planner {
450        use crate::{Fft, FftDirection, FftNum};
451        use std::sync::Arc;
452
453        /// The Neon FFT planner creates new FFT algorithm instances using a mix of scalar and Neon accelerated algorithms.
454        /// It is supported when using the 64-bit AArch64 instruction set.
455        ///
456        /// RustFFT has several FFT algorithms available. For a given FFT size, the `FftPlannerNeon` decides which of the
457        /// available FFT algorithms to use and then initializes them.
458        ///
459        /// ~~~
460        /// // Perform a forward Fft of size 1234
461        /// use std::sync::Arc;
462        /// use rustfft::{FftPlannerNeon, num_complex::Complex};
463        ///
464        /// if let Ok(mut planner) = FftPlannerNeon::new() {
465        ///   let fft = planner.plan_fft_forward(1234);
466        ///
467        ///   let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234];
468        ///   fft.process(&mut buffer);
469        ///
470        ///   // The FFT instance returned by the planner has the type `Arc<dyn Fft<T>>`,
471        ///   // where T is the numeric type, ie f32 or f64, so it's cheap to clone
472        ///   let fft_clone = Arc::clone(&fft);
473        /// }
474        /// ~~~
475        ///
476        /// If you plan on creating multiple FFT instances, it is recommended to reuse the same planner for all of them. This
477        /// is because the planner re-uses internal data across FFT instances wherever possible, saving memory and reducing
478        /// setup time. (FFT instances created with one planner will never re-use data and buffers with FFT instances created
479        /// by a different planner)
480        ///
481        /// Each FFT instance owns [`Arc`s](std::sync::Arc) to its internal data, rather than borrowing it from the planner, so it's perfectly
482        /// safe to drop the planner after creating Fft instances.
483        pub struct FftPlannerNeon<T: FftNum> {
484            _phantom: std::marker::PhantomData<T>,
485        }
486        impl<T: FftNum> FftPlannerNeon<T> {
487            /// Creates a new `FftPlannerNeon` instance.
488            ///
489            /// Returns `Ok(planner_instance)` if this machine has the required instruction sets.
490            /// Returns `Err(())` if some instruction sets are missing.
491            pub fn new() -> Result<Self, ()> {
492                Err(())
493            }
494            /// Returns a `Fft` instance which uses Neon instructions to compute FFTs of size `len`.
495            ///
496            /// If the provided `direction` is `FftDirection::Forward`, the returned instance will compute forward FFTs. If it's `FftDirection::Inverse`, it will compute inverse FFTs.
497            ///
498            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
499            pub fn plan_fft(&mut self, _len: usize, _direction: FftDirection) -> Arc<dyn Fft<T>> {
500                unreachable!()
501            }
502            /// Returns a `Fft` instance which uses Neon instructions to compute forward FFTs of size `len`.
503            ///
504            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
505            pub fn plan_fft_forward(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
506                unreachable!()
507            }
508            /// Returns a `Fft` instance which uses Neon instructions to compute inverse FFTs of size `len.
509            ///
510            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
511            pub fn plan_fft_inverse(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
512                unreachable!()
513            }
514        }
515    }
516}
517
518pub use self::neon::neon_planner::FftPlannerNeon;
519
520#[cfg(all(target_arch = "wasm32", feature = "wasm_simd"))]
521mod wasm_simd;
522
523// If we're not compiling to WebAssembly, or if the "wasm_simd" feature was disabled, keep a stub implementation around that has the same API, but does nothing
524// That way, users can write code using the WASM planner and compile it on any platform
525#[cfg(not(all(target_arch = "wasm32", feature = "wasm_simd")))]
526mod wasm_simd {
527    pub mod wasm_simd_planner {
528        use crate::{Fft, FftDirection, FftNum};
529        use std::sync::Arc;
530
531        /// The WASM FFT planner creates new FFT algorithm instances using a mix of scalar and WASM SIMD accelerated algorithms.
532        /// It is supported when using fairly recent browser versions as outlined in [the WebAssembly roadmap](https://webassembly.org/roadmap/).
533        ///
534        /// RustFFT has several FFT algorithms available. For a given FFT size, `FftPlannerWasmSimd` decides which of the
535        /// available FFT algorithms to use and then initializes them.
536        ///
537        /// ~~~
538        /// // Perform a forward Fft of size 1234
539        /// use std::sync::Arc;
540        /// use rustfft::{FftPlannerWasmSimd, num_complex::Complex};
541        ///
542        /// if let Ok(mut planner) = FftPlannerWasmSimd::new() {
543        ///   let fft = planner.plan_fft_forward(1234);
544        ///
545        ///   let mut buffer = vec![Complex{ re: 0.0f32, im: 0.0f32 }; 1234];
546        ///   fft.process(&mut buffer);
547        ///
548        ///   // The FFT instance returned by the planner has the type `Arc<dyn Fft<T>>`,
549        ///   // where T is the numeric type, ie f32 or f64, so it's cheap to clone
550        ///   let fft_clone = Arc::clone(&fft);
551        /// }
552        /// ~~~
553        ///
554        /// If you plan on creating multiple FFT instances, it is recommended to reuse the same planner for all of them. This
555        /// is because the planner re-uses internal data across FFT instances wherever possible, saving memory and reducing
556        /// setup time. (FFT instances created with one planner will never re-use data and buffers with FFT instances created
557        /// by a different planner)
558        ///
559        /// Each FFT instance owns [`Arc`s](std::sync::Arc) to its internal data, rather than borrowing it from the planner, so it's perfectly
560        /// safe to drop the planner after creating Fft instances.
561        pub struct FftPlannerWasmSimd<T: FftNum> {
562            _phantom: std::marker::PhantomData<T>,
563        }
564        impl<T: FftNum> FftPlannerWasmSimd<T> {
565            /// Creates a new `FftPlannerWasmSimd` instance.
566            ///
567            /// Returns `Ok(planner_instance)` if this machine has the required instruction sets.
568            /// Returns `Err(())` if some instruction sets are missing.
569            pub fn new() -> Result<Self, ()> {
570                Err(())
571            }
572            /// Returns a `Fft` instance which uses WebAssembly SIMD instructions to compute FFTs of size `len`.
573            ///
574            /// If the provided `direction` is `FftDirection::Forward`, the returned instance will compute forward FFTs. If it's `FftDirection::Inverse`, it will compute inverse FFTs.
575            ///
576            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
577            pub fn plan_fft(&mut self, _len: usize, _direction: FftDirection) -> Arc<dyn Fft<T>> {
578                unreachable!()
579            }
580            /// Returns a `Fft` instance which uses WebAssembly SIMD instructions to compute forward FFTs of size `len`.
581            ///
582            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
583            pub fn plan_fft_forward(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
584                unreachable!()
585            }
586            /// Returns a `Fft` instance which uses WebAssembly SIMD instructions to compute inverse FFTs of size `len.
587            ///
588            /// If this is called multiple times, the planner will attempt to re-use internal data between calls, reducing memory usage and FFT initialization time.
589            pub fn plan_fft_inverse(&mut self, _len: usize) -> Arc<dyn Fft<T>> {
590                unreachable!()
591            }
592        }
593    }
594}
595
596pub use self::wasm_simd::wasm_simd_planner::FftPlannerWasmSimd;
597
598#[cfg(test)]
599mod test_utils;