Skip to main content

oxifft/api/
types.rs

1//! Public type definitions for the OxiFFT API.
2
3use core::fmt;
4use core::ops::BitOr;
5
6/// Transform direction.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum Direction {
10    /// Forward transform (analysis): time domain → frequency domain
11    Forward,
12    /// Backward/Inverse transform (synthesis): frequency domain → time domain
13    Backward,
14}
15
16impl Direction {
17    /// Get the sign for the exponential: -1 for forward, +1 for backward.
18    ///
19    /// This matches the FFTW convention where the forward (analysis) transform
20    /// uses a negative exponent and the backward (synthesis) transform uses a
21    /// positive exponent.
22    #[must_use]
23    pub const fn sign(self) -> i32 {
24        match self {
25            Self::Forward => -1,
26            Self::Backward => 1,
27        }
28    }
29}
30
31impl TryFrom<i32> for Direction {
32    type Error = InvalidDirection;
33
34    /// Construct a `Direction` from its FFTW-style sign convention:
35    /// `-1` means [`Direction::Forward`] (negative exponent) and
36    /// `+1` means [`Direction::Backward`] (positive exponent).
37    ///
38    /// # Errors
39    ///
40    /// Returns [`InvalidDirection`] if `value` is not `-1` or `1`.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use oxifft::Direction;
46    ///
47    /// let fwd = Direction::try_from(-1_i32).expect("forward");
48    /// assert_eq!(fwd, Direction::Forward);
49    ///
50    /// let bwd = Direction::try_from(1_i32).expect("backward");
51    /// assert_eq!(bwd, Direction::Backward);
52    ///
53    /// assert!(Direction::try_from(0_i32).is_err());
54    /// ```
55    fn try_from(value: i32) -> Result<Self, Self::Error> {
56        match value {
57            -1 => Ok(Self::Forward),
58            1 => Ok(Self::Backward),
59            n => Err(InvalidDirection(n)),
60        }
61    }
62}
63
64/// Error returned when an integer cannot be converted to a [`Direction`].
65///
66/// Valid values are `-1` (forward, negative exponent) and `1` (backward, positive exponent),
67/// following the FFTW sign convention.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub struct InvalidDirection(pub i32);
70
71impl fmt::Display for InvalidDirection {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(
74            f,
75            "invalid direction value {}: expected -1 (forward) or 1 (backward)",
76            self.0
77        )
78    }
79}
80
81impl core::error::Error for InvalidDirection {}
82
83/// Planning flags that control algorithm selection.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
85pub struct Flags(u32);
86
87impl Flags {
88    /// Use heuristics only, don't measure (fastest planning, may not be optimal).
89    pub const ESTIMATE: Self = Self(0);
90
91    /// Measure a few algorithms and pick the best.
92    pub const MEASURE: Self = Self(1 << 0);
93
94    /// Try harder to find the optimal algorithm.
95    pub const PATIENT: Self = Self(1 << 1);
96
97    /// Try all possible algorithms exhaustively.
98    pub const EXHAUSTIVE: Self = Self(1 << 2);
99
100    /// Preserve input array (default behavior).
101    pub const PRESERVE_INPUT: Self = Self(1 << 3);
102
103    /// Allow destroying input array for potentially better performance.
104    pub const DESTROY_INPUT: Self = Self(1 << 4);
105
106    /// Plan for unaligned data.
107    pub const UNALIGNED: Self = Self(1 << 5);
108
109    /// Check if MEASURE flag is set.
110    #[must_use]
111    pub const fn is_measure(self) -> bool {
112        self.0 & Self::MEASURE.0 != 0
113    }
114
115    /// Check if PATIENT flag is set.
116    #[must_use]
117    pub const fn is_patient(self) -> bool {
118        self.0 & Self::PATIENT.0 != 0
119    }
120
121    /// Check if EXHAUSTIVE flag is set.
122    #[must_use]
123    pub const fn is_exhaustive(self) -> bool {
124        self.0 & Self::EXHAUSTIVE.0 != 0
125    }
126
127    /// Check if input destruction is allowed.
128    #[must_use]
129    pub const fn can_destroy_input(self) -> bool {
130        self.0 & Self::DESTROY_INPUT.0 != 0
131    }
132}
133
134impl BitOr for Flags {
135    type Output = Self;
136
137    fn bitor(self, rhs: Self) -> Self::Output {
138        Self(self.0 | rhs.0)
139    }
140}
141
142/// Real-to-real transform kind (DCT/DST variants).
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144#[non_exhaustive]
145pub enum R2rKind {
146    /// DCT-I (REDFT00)
147    DctI,
148    /// DCT-II (REDFT10) - "the DCT"
149    DctII,
150    /// DCT-III (REDFT01) - inverse of DCT-II
151    DctIII,
152    /// DCT-IV (REDFT11)
153    DctIV,
154    /// DST-I (RODFT00)
155    DstI,
156    /// DST-II (RODFT10)
157    DstII,
158    /// DST-III (RODFT01)
159    DstIII,
160    /// DST-IV (RODFT11)
161    DstIV,
162    /// Discrete Hartley Transform
163    Dht,
164    /// Half-complex to real (used internally)
165    Hc2r,
166    /// Real to half-complex (used internally)
167    R2hc,
168}