Skip to main content

mesh_sieve/data/
storage.rs

1//! Pluggable storage for Section buffers.
2//!
3//! This trait abstracts how Section's flat buffer is stored (e.g., Vec, mmap, GPU).
4//! The initial design keeps CPU-slice semantics to minimize churn. Future steps
5//! can add async/mapped variants without touching Section's public API.
6
7use core::fmt::{self, Debug};
8
9use crate::data::refine::delta::SliceDelta;
10use crate::data::slice_storage::SliceStorage;
11use crate::mesh_error::MeshSieveError;
12
13/// Contiguous, indexable storage for `V` with slice access.
14///
15/// Notes:
16/// - Returning slices keeps this step localized. A GPU/mmap backend can be
17///   implemented later by staging into host memory (or by extending the trait).
18pub trait Storage<V>: Debug {
19    /// Construct a buffer of `len`, filled with `fill`.
20    fn with_len(len: usize, fill: V) -> Self
21    where
22        V: Clone;
23
24    /// Current length in elements.
25    fn len(&self) -> usize;
26
27    /// Resize to `new_len`, filling new cells with `fill`.
28    fn resize(&mut self, new_len: usize, fill: V)
29    where
30        V: Clone;
31
32    /// Entire read-only buffer.
33    fn as_slice(&self) -> &[V];
34
35    /// Entire mutable buffer.
36    fn as_mut_slice(&mut self) -> &mut [V];
37
38    /// Copy `src` into the range `[offset .. offset + src.len())`.
39    fn write_at(&mut self, offset: usize, src: &[V]) -> Result<(), MeshSieveError>
40    where
41        V: Clone,
42    {
43        let end =
44            offset
45                .checked_add(src.len())
46                .ok_or_else(|| MeshSieveError::ScatterChunkMismatch {
47                    offset,
48                    len: src.len(),
49                })?;
50        let buf = self.as_mut_slice();
51        let dst = buf
52            .get_mut(offset..end)
53            .ok_or(MeshSieveError::ScatterChunkMismatch {
54                offset,
55                len: src.len(),
56            })?;
57        dst.clone_from_slice(src);
58        Ok(())
59    }
60
61    /// Read the range `[offset .. offset + len)` into `dst`.
62    fn read_into(&self, offset: usize, len: usize, dst: &mut [V]) -> Result<(), MeshSieveError>
63    where
64        V: Clone,
65    {
66        if dst.len() != len {
67            return Err(MeshSieveError::ScatterLengthMismatch {
68                expected: len,
69                found: dst.len(),
70            });
71        }
72        let end = offset
73            .checked_add(len)
74            .ok_or_else(|| MeshSieveError::ScatterChunkMismatch { offset, len })?;
75        let buf = self.as_slice();
76        let src = buf
77            .get(offset..end)
78            .ok_or(MeshSieveError::ScatterChunkMismatch { offset, len })?;
79        dst.clone_from_slice(src);
80        Ok(())
81    }
82}
83
84/// `Vec`-backed storage (default).
85#[derive(Clone)]
86pub struct VecStorage<V>(pub(crate) Vec<V>);
87
88impl<V> Debug for VecStorage<V> {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        f.debug_struct("VecStorage")
91            .field("len", &self.0.len())
92            .finish()
93    }
94}
95
96impl<V> Storage<V> for VecStorage<V> {
97    fn with_len(len: usize, fill: V) -> Self
98    where
99        V: Clone,
100    {
101        Self(vec![fill; len])
102    }
103
104    fn len(&self) -> usize {
105        self.0.len()
106    }
107
108    fn resize(&mut self, new_len: usize, fill: V)
109    where
110        V: Clone,
111    {
112        self.0.resize(new_len, fill);
113    }
114
115    fn as_slice(&self) -> &[V] {
116        &self.0
117    }
118
119    fn as_mut_slice(&mut self) -> &mut [V] {
120        &mut self.0
121    }
122}
123
124impl<V> From<Vec<V>> for VecStorage<V> {
125    fn from(v: Vec<V>) -> Self {
126        Self(v)
127    }
128}
129
130impl<V> VecStorage<V> {
131    pub fn into_inner(self) -> Vec<V> {
132        self.0
133    }
134}
135
136impl<V> SliceStorage<V> for VecStorage<V>
137where
138    V: Clone + Default + Send + Sync,
139{
140    fn total_len(&self) -> usize {
141        self.0.len()
142    }
143
144    fn resize(&mut self, new_len: usize) -> Result<(), MeshSieveError> {
145        self.0.resize(new_len, V::default());
146        Ok(())
147    }
148
149    fn read_slice(&self, offset: usize, len: usize) -> Result<Vec<V>, MeshSieveError> {
150        let end = offset
151            .checked_add(len)
152            .ok_or(MeshSieveError::ScatterChunkMismatch { offset, len })?;
153        let src = self
154            .0
155            .get(offset..end)
156            .ok_or(MeshSieveError::ScatterChunkMismatch { offset, len })?;
157        Ok(src.to_vec())
158    }
159
160    fn write_slice(&mut self, offset: usize, src: &[V]) -> Result<(), MeshSieveError> {
161        let end = offset
162            .checked_add(src.len())
163            .ok_or(MeshSieveError::ScatterChunkMismatch {
164                offset,
165                len: src.len(),
166            })?;
167        let dst = self
168            .0
169            .get_mut(offset..end)
170            .ok_or(MeshSieveError::ScatterChunkMismatch {
171                offset,
172                len: src.len(),
173            })?;
174        dst.clone_from_slice(src);
175        Ok(())
176    }
177
178    fn apply_delta<D: SliceDelta<V> + 'static>(
179        &mut self,
180        src_off: usize,
181        dst_off: usize,
182        len: usize,
183        delta: &D,
184    ) -> Result<(), MeshSieveError> {
185        if len == 0 {
186            return Ok(());
187        }
188        let src_end = src_off
189            .checked_add(len)
190            .ok_or(MeshSieveError::ScatterChunkMismatch {
191                offset: src_off,
192                len,
193            })?;
194        let dst_end = dst_off
195            .checked_add(len)
196            .ok_or(MeshSieveError::ScatterChunkMismatch {
197                offset: dst_off,
198                len,
199            })?;
200        if src_end > self.0.len() {
201            return Err(MeshSieveError::ScatterChunkMismatch {
202                offset: src_off,
203                len,
204            });
205        }
206        if dst_end > self.0.len() {
207            return Err(MeshSieveError::ScatterChunkMismatch {
208                offset: dst_off,
209                len,
210            });
211        }
212        let disjoint = src_end <= dst_off || dst_end <= src_off;
213        if disjoint {
214            if src_off < dst_off {
215                let (a, b) = self.0.split_at_mut(dst_off);
216                let src = &a[src_off..src_end];
217                let dst = &mut b[..len];
218                delta.apply(src, dst)?;
219            } else {
220                let (a, b) = self.0.split_at_mut(src_off);
221                let dst = &mut a[dst_off..dst_end];
222                let src = &b[..len];
223                delta.apply(src, dst)?;
224            }
225        } else {
226            let src_copy: Vec<V> = self.0[src_off..src_end].to_vec();
227            let dst = &mut self.0[dst_off..dst_end];
228            delta.apply(&src_copy, dst)?;
229        }
230        Ok(())
231    }
232}