fpm_rs/backend/traits.rs
1use std::any::Any;
2
3use num_complex::Complex64;
4
5use crate::Result;
6
7/// Direction of an unnormalized two-dimensional complex FFT.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum FftDirection {
10 /// Spatial domain to centered or uncentered spectrum as managed by the caller.
11 Forward,
12 /// Spectrum to spatial domain, normalized by the backend to invert [`Self::Forward`].
13 Inverse,
14}
15
16/// Memory domain in which a backend buffer resides.
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum MemoryLocation {
19 /// Ordinary CPU-addressable host memory.
20 Host,
21 /// Accelerator/device memory not directly represented by a host slice.
22 Device,
23}
24
25/// Feature declaration returned by an execution backend.
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub struct BackendCapabilities {
28 /// Memory domain preferred for persistent reconstruction state.
29 pub preferred_memory: MemoryLocation,
30 /// Whether [`Backend::resident_backend`] exposes typed persistent buffers.
31 pub resident_buffers: bool,
32}
33
34impl Default for BackendCapabilities {
35 fn default() -> Self {
36 Self {
37 preferred_memory: MemoryLocation::Host,
38 resident_buffers: false,
39 }
40 }
41}
42
43/// Type-erased contiguous buffer of [`Complex64`] values owned by a resident backend.
44pub trait ComplexBuffer: Send + Sync {
45 /// Returns the number of complex elements.
46 fn len(&self) -> usize;
47 /// Returns whether the buffer contains no elements.
48 fn is_empty(&self) -> bool {
49 self.len() == 0
50 }
51 /// Returns the buffer's memory domain.
52 fn location(&self) -> MemoryLocation;
53 /// Exposes immutable type erasure for backend-specific downcasting.
54 fn as_any(&self) -> &dyn Any;
55 /// Exposes mutable type erasure for backend-specific downcasting.
56 fn as_any_mut(&mut self) -> &mut dyn Any;
57}
58
59/// Type-erased contiguous buffer of `f64` values owned by a resident backend.
60pub trait RealBuffer: Send + Sync {
61 /// Returns the number of real elements.
62 fn len(&self) -> usize;
63 /// Returns whether the buffer contains no elements.
64 fn is_empty(&self) -> bool {
65 self.len() == 0
66 }
67 /// Returns the buffer's memory domain.
68 fn location(&self) -> MemoryLocation;
69 /// Exposes immutable type erasure for backend-specific downcasting.
70 fn as_any(&self) -> &dyn Any;
71 /// Exposes mutable type erasure for backend-specific downcasting.
72 fn as_any_mut(&mut self) -> &mut dyn Any;
73}
74
75/// Optional typed-buffer operations for backends that can keep reconstruction
76/// state resident in their preferred memory domain.
77pub trait ResidentBackend: Send + Sync {
78 /// Allocates `len` uninitialized or zeroed complex elements according to backend policy.
79 fn allocate_complex(&self, len: usize) -> Result<Box<dyn ComplexBuffer>>;
80 /// Allocates `len` uninitialized or zeroed real elements according to backend policy.
81 fn allocate_real(&self, len: usize) -> Result<Box<dyn RealBuffer>>;
82 /// Copies a host complex slice into an equal-length resident buffer.
83 fn upload_complex(
84 &self,
85 destination: &mut dyn ComplexBuffer,
86 source: &[Complex64],
87 ) -> Result<()>;
88 /// Copies an equal-length resident complex buffer into a host slice.
89 fn download_complex(
90 &self,
91 source: &dyn ComplexBuffer,
92 destination: &mut [Complex64],
93 ) -> Result<()>;
94 /// Copies a host real slice into an equal-length resident buffer.
95 fn upload_real(&self, destination: &mut dyn RealBuffer, source: &[f64]) -> Result<()>;
96 /// Copies an equal-length resident real buffer into a host slice.
97 fn download_real(&self, source: &dyn RealBuffer, destination: &mut [f64]) -> Result<()>;
98 /// Applies an in-place two-dimensional FFT to `values` shaped `(height, width)`.
99 fn fft2_resident(
100 &self,
101 values: &mut dyn ComplexBuffer,
102 shape: (usize, usize),
103 direction: FftDirection,
104 ) -> Result<()>;
105}
106
107/// Minimal backend boundary. Buffers stay owned by reconstruction state.
108pub trait Backend: Send + Sync {
109 /// Reports memory and resident-buffer capabilities.
110 fn capabilities(&self) -> BackendCapabilities {
111 BackendCapabilities::default()
112 }
113
114 /// Returns optional resident-buffer operations when declared by [`Self::capabilities`].
115 fn resident_backend(&self) -> Option<&dyn ResidentBackend> {
116 None
117 }
118
119 /// Applies an in-place normalized 2-D FFT to a row-major host buffer.
120 ///
121 /// `values` must contain `height * width` elements and `column_scratch` must fit the
122 /// larger axis required by the implementation.
123 fn fft2(
124 &self,
125 values: &mut [Complex64],
126 shape: (usize, usize),
127 direction: FftDirection,
128 column_scratch: &mut [Complex64],
129 ) -> Result<()>;
130}