1use crate::backend::BackendContext;
7use crate::error::FFTResult;
8use crate::plan_cache::get_global_cache;
9use crate::worker_pool::get_global_pool;
10
11pub struct FftContext {
13 backend_context: Option<BackendContext>,
14 previous_workers: Option<usize>,
15 previous_cache_enabled: Option<bool>,
16 worker_pool: &'static crate::worker_pool::WorkerPool,
17 plan_cache: &'static crate::plan_cache::PlanCache,
18}
19
20impl FftContext {
21 pub fn new() -> Self {
23 Self {
24 backend_context: None,
25 previous_workers: None,
26 previous_cache_enabled: None,
27 worker_pool: get_global_pool(),
28 plan_cache: get_global_cache(),
29 }
30 }
31}
32
33impl Default for FftContext {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl FftContext {
40 pub fn with_backend(mut self, backendname: &str) -> FFTResult<Self> {
42 self.backend_context = Some(BackendContext::new(backendname)?);
43 Ok(self)
44 }
45
46 pub fn with_workers(mut self, _numworkers: usize) -> Self {
48 self.previous_workers = Some(self.worker_pool.get_workers());
49 self
52 }
53
54 pub fn with_cache(mut self, enabled: bool) -> Self {
56 self.previous_cache_enabled = Some(self.plan_cache.is_enabled());
57 self.plan_cache.set_enabled(enabled);
58 self
59 }
60
61 pub fn __enter__(self) -> Self {
63 self
64 }
65
66 pub fn __exit__(self) {
68 }
70}
71
72impl Drop for FftContext {
73 fn drop(&mut self) {
74 if let Some(enabled) = self.previous_cache_enabled {
76 self.plan_cache.set_enabled(enabled);
77 }
78
79 }
84}
85
86pub struct FftContextBuilder {
88 backend: Option<String>,
89 workers: Option<usize>,
90 cache_enabled: Option<bool>,
91 cache_size: Option<usize>,
92 cache_ttl: Option<std::time::Duration>,
93}
94
95impl FftContextBuilder {
96 pub fn new() -> Self {
98 Self {
99 backend: None,
100 workers: None,
101 cache_enabled: None,
102 cache_size: None,
103 cache_ttl: None,
104 }
105 }
106
107 pub fn backend(mut self, name: &str) -> Self {
109 self.backend = Some(name.to_string());
110 self
111 }
112
113 pub fn workers(mut self, count: usize) -> Self {
115 self.workers = Some(count);
116 self
117 }
118
119 pub fn cache_enabled(mut self, enabled: bool) -> Self {
121 self.cache_enabled = Some(enabled);
122 self
123 }
124
125 pub fn cache_size(mut self, size: usize) -> Self {
127 self.cache_size = Some(size);
128 self
129 }
130
131 pub fn cache_ttl(mut self, ttl: std::time::Duration) -> Self {
133 self.cache_ttl = Some(ttl);
134 self
135 }
136
137 pub fn build(self) -> FFTResult<FftContext> {
139 let mut context = FftContext::new();
140
141 if let Some(backend) = self.backend {
142 context = context.with_backend(&backend)?;
143 }
144
145 if let Some(workers) = self.workers {
146 context = context.with_workers(workers);
147 }
148
149 if let Some(enabled) = self.cache_enabled {
150 context = context.with_cache(enabled);
151 }
152
153 Ok(context)
157 }
158}
159
160impl Default for FftContextBuilder {
161 fn default() -> Self {
162 Self::new()
163 }
164}
165
166#[allow(dead_code)]
168pub fn fft_context() -> FftContextBuilder {
169 FftContextBuilder::new()
170}
171
172pub struct FftSettingsGuard {
174 _context: FftContext,
175}
176
177impl FftSettingsGuard {
178 pub fn new(context: FftContext) -> Self {
179 Self { _context: context }
180 }
181}
182
183#[allow(dead_code)]
185pub fn with_fft_settings<F, R>(builder: FftContextBuilder, f: F) -> FFTResult<R>
186where
187 F: FnOnce() -> R,
188{
189 let context = builder.build()?;
190 let _guard = FftSettingsGuard::new(context);
191 Ok(f())
192}
193
194#[allow(dead_code)]
196pub fn with_backend<F, R>(backend: &str, f: F) -> FFTResult<R>
197where
198 F: FnOnce() -> R,
199{
200 with_fft_settings(fft_context().backend(backend), f)
201}
202
203#[allow(dead_code)]
205pub fn with_workers<F, R>(workers: usize, f: F) -> FFTResult<R>
206where
207 F: FnOnce() -> R,
208{
209 with_fft_settings(fft_context().workers(workers), f)
210}
211
212#[allow(dead_code)]
214pub fn without_cache<F, R>(f: F) -> FFTResult<R>
215where
216 F: FnOnce() -> R,
217{
218 with_fft_settings(fft_context().cache_enabled(false), f)
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_context_builder() {
227 let builder = fft_context()
228 .backend("rustfft")
229 .workers(4)
230 .cache_enabled(true);
231
232 let context = builder.build().unwrap();
233 drop(context);
235 }
236
237 #[test]
238 fn test_with_backend() {
239 let result = with_backend("rustfft", || {
240 42
242 });
243
244 assert_eq!(result.unwrap(), 42);
245 }
246
247 #[test]
248 fn test_with_workers() {
249 let result = with_workers(2, || {
250 84
252 });
253
254 assert_eq!(result.unwrap(), 84);
255 }
256
257 #[test]
258 fn test_without_cache() {
259 let result = without_cache(|| {
260 168
262 });
263
264 assert_eq!(result.unwrap(), 168);
265 }
266
267 #[test]
268 fn test_combined_settings() {
269 let result = with_fft_settings(
270 fft_context()
271 .backend("rustfft")
272 .workers(4)
273 .cache_enabled(false),
274 || {
275 336
277 },
278 );
279
280 assert_eq!(result.unwrap(), 336);
281 }
282}