Skip to main content

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}