1use crate::data::atlas::Atlas;
12use crate::data::refine::delta::SliceDelta;
13use crate::data::storage::Storage;
14use crate::debug_invariants::DebugInvariants;
15use crate::mesh_error::MeshSieveError;
16use crate::topology::cache::InvalidateCache;
17use crate::topology::point::PointId;
18
19#[derive(Clone, Debug)]
21pub struct ScatterPlan {
22 pub(crate) atlas_version: u64,
23 pub(crate) spans: Vec<(usize, usize)>,
24}
25
26use core::marker::PhantomData;
36
37#[derive(Clone, Debug)]
38pub struct Section<V, S: Storage<V>> {
39 atlas: Atlas,
41 data: S,
43 _marker: PhantomData<V>,
44}
45
46#[derive(Clone, Debug)]
48pub enum ResizePolicy<V> {
49 ZeroInit,
51 PreservePrefix,
53 PreserveSuffix,
55 PadWith(V),
57}
58
59impl<V, S> Section<V, S>
60where
61 S: Storage<V>,
62{
63 #[inline]
69 pub fn try_restrict(&self, p: PointId) -> Result<&[V], MeshSieveError> {
70 let (offset, len) = self
71 .atlas
72 .get(p)
73 .ok_or(MeshSieveError::PointNotInAtlas(p))?;
74 self.data
75 .as_slice()
76 .get(offset..offset + len)
77 .ok_or(MeshSieveError::MissingSectionPoint(p))
78 }
79
80 #[inline]
86 pub fn try_restrict_mut(&mut self, p: PointId) -> Result<&mut [V], MeshSieveError> {
87 let (offset, len) = self
88 .atlas
89 .get(p)
90 .ok_or(MeshSieveError::PointNotInAtlas(p))?;
91 self.data
92 .as_mut_slice()
93 .get_mut(offset..offset + len)
94 .ok_or(MeshSieveError::MissingSectionPoint(p))
95 }
96
97 #[inline]
105 pub fn atlas(&self) -> &Atlas {
106 &self.atlas
107 }
108
109 pub fn iter(&self) -> impl Iterator<Item = (PointId, &[V])> + '_ {
111 self.atlas
112 .points()
113 .filter_map(move |pid| self.try_restrict(pid).ok().map(|sl| (pid, sl)))
114 }
115
116 #[inline]
118 pub fn as_flat_slice(&self) -> &[V] {
119 self.data.as_slice()
120 }
121
122 pub fn for_each_in_order_mut<F>(&mut self, mut f: F)
124 where
125 F: FnMut(PointId, &mut [V]),
126 {
127 #[cfg(any(
128 debug_assertions,
129 feature = "strict-invariants",
130 feature = "check-invariants"
131 ))]
132 self.debug_assert_invariants();
133 for pid in self.atlas.points() {
134 let (off, len) = self.atlas.get(pid).expect("invariants");
135 let buf = self.data.as_mut_slice();
136 f(pid, &mut buf[off..off + len]);
137 }
138 crate::topology::cache::InvalidateCache::invalidate_cache(self);
139 #[cfg(any(
140 debug_assertions,
141 feature = "strict-invariants",
142 feature = "check-invariants"
143 ))]
144 self.debug_assert_invariants();
145 }
146
147 pub fn for_each_in_order<F>(&self, mut f: F)
149 where
150 F: FnMut(PointId, &[V]),
151 {
152 #[cfg(any(
153 debug_assertions,
154 feature = "strict-invariants",
155 feature = "check-invariants"
156 ))]
157 self.debug_assert_invariants();
158 for pid in self.atlas.points() {
159 let (off, len) = self.atlas.get(pid).expect("invariants");
160 let buf = self.data.as_slice();
161 f(pid, &buf[off..off + len]);
162 }
163 }
164
165 #[inline]
166 fn spans_cover_contiguously(spans: &[(usize, usize)], total: usize) -> bool {
167 if spans.is_empty() {
168 return total == 0;
169 }
170 let mut expected_off = 0usize;
171 for &(off, len) in spans {
172 if off != expected_off {
173 return false;
174 }
175 match expected_off.checked_add(len) {
176 Some(next) => expected_off = next,
177 None => return false,
178 }
179 }
180 expected_off == total
181 }
182}
183
184impl<V: Clone + Default, S: Storage<V>> Section<V, S> {
185 #[inline]
187 pub fn gather_in_order(&self) -> Vec<V> {
188 self.data.as_slice().to_vec()
189 }
190
191 pub fn try_set(&mut self, p: PointId, val: &[V]) -> Result<(), MeshSieveError> {
197 let target = self.try_restrict_mut(p)?;
198 let expected = target.len();
199 let found = val.len();
200 if expected != found {
201 return Err(MeshSieveError::SliceLengthMismatch {
202 point: p,
203 expected,
204 found,
205 });
206 }
207 target.clone_from_slice(val);
208 crate::topology::cache::InvalidateCache::invalidate_cache(self);
209 #[cfg(any(
210 debug_assertions,
211 feature = "strict-invariants",
212 feature = "check-invariants"
213 ))]
214 self.debug_assert_invariants();
215 Ok(())
216 }
217
218 pub fn try_remove_point(&mut self, p: PointId) -> Result<(), MeshSieveError> {
229 let old_atlas = self.atlas.clone();
230 self.atlas.remove_point(p)?;
231 let total_len_new = self.atlas.total_len();
232 let mut new_data = Vec::with_capacity(total_len_new);
233 let buf = self.data.as_slice();
234 for pid in self.atlas.points() {
235 let (old_offset, old_len) = old_atlas
236 .get(pid)
237 .ok_or(MeshSieveError::MissingSectionPoint(pid))?;
238 let old_slice = buf
239 .get(old_offset..old_offset + old_len)
240 .ok_or(MeshSieveError::MissingSectionPoint(pid))?;
241 new_data.extend_from_slice(old_slice);
242 }
243 let mut next = S::with_len(total_len_new, V::default());
244 next.as_mut_slice().clone_from_slice(&new_data);
245 self.data = next;
246 crate::topology::cache::InvalidateCache::invalidate_cache(self);
247 #[cfg(any(
248 debug_assertions,
249 feature = "strict-invariants",
250 feature = "check-invariants"
251 ))]
252 self.debug_assert_invariants();
253 Ok(())
254 }
255
256 pub fn try_apply_delta_between_points<D: SliceDelta<V>>(
272 &mut self,
273 src_point: PointId,
274 dst_point: PointId,
275 delta: &D,
276 ) -> Result<(), MeshSieveError> {
277 use MeshSieveError::*;
278
279 #[cfg(any(
280 debug_assertions,
281 feature = "strict-invariants",
282 feature = "check-invariants"
283 ))]
284 self.debug_assert_invariants();
285
286 let (soff, slen) = self
287 .atlas
288 .get(src_point)
289 .ok_or(PointNotInAtlas(src_point))?;
290 let (doff, dlen) = self
291 .atlas
292 .get(dst_point)
293 .ok_or(PointNotInAtlas(dst_point))?;
294
295 if slen != dlen {
296 return Err(SliceLengthMismatch {
297 point: dst_point,
298 expected: slen,
299 found: dlen,
300 });
301 }
302
303 let src_end = soff.checked_add(slen).ok_or(ScatterChunkMismatch {
304 offset: soff,
305 len: slen,
306 })?;
307 let dst_end = doff.checked_add(dlen).ok_or(ScatterChunkMismatch {
308 offset: doff,
309 len: dlen,
310 })?;
311
312 if src_end > self.data.len() {
313 return Err(MissingSectionPoint(src_point));
314 }
315 if dst_end > self.data.len() {
316 return Err(MissingSectionPoint(dst_point));
317 }
318
319 if slen == 0 {
320 crate::topology::cache::InvalidateCache::invalidate_cache(self);
321 #[cfg(any(
322 debug_assertions,
323 feature = "strict-invariants",
324 feature = "check-invariants"
325 ))]
326 self.debug_assert_invariants();
327 return Ok(());
328 }
329
330 let disjoint = src_end <= doff || dst_end <= soff;
331
332 if disjoint {
333 let data = self.data.as_mut_slice();
334 if soff < doff {
335 let (a, b) = data.split_at_mut(doff);
336 let src = &a[soff..src_end];
337 let dst = &mut b[0..dlen];
338 delta.apply(src, dst)?;
339 } else {
340 let (a, b) = data.split_at_mut(soff);
341 let dst = &mut a[doff..dst_end];
342 let src = &b[0..slen];
343 delta.apply(src, dst)?;
344 }
345 } else {
346 let src_copy: Vec<V> = self.data.as_slice()[soff..src_end].to_vec();
347 let dst = &mut self.data.as_mut_slice()[doff..dst_end];
348 delta.apply(&src_copy, dst)?;
349 }
350
351 crate::topology::cache::InvalidateCache::invalidate_cache(self);
352 #[cfg(any(
353 debug_assertions,
354 feature = "strict-invariants",
355 feature = "check-invariants"
356 ))]
357 self.debug_assert_invariants();
358 Ok(())
359 }
360
361 pub fn try_scatter_from(
373 &mut self,
374 other: &[V],
375 atlas_map: &[(usize, usize)],
376 ) -> Result<(), MeshSieveError> {
377 if other.len() == self.data.len()
378 && Self::spans_cover_contiguously(atlas_map, self.data.len())
379 {
380 self.data.as_mut_slice().clone_from_slice(other);
381 crate::topology::cache::InvalidateCache::invalidate_cache(self);
382 #[cfg(any(
383 debug_assertions,
384 feature = "strict-invariants",
385 feature = "check-invariants"
386 ))]
387 self.debug_assert_invariants();
388 return Ok(());
389 }
390
391 let total_expected: usize = atlas_map.iter().map(|&(_, l)| l).sum();
392 let found = other.len();
393 if total_expected != found {
394 return Err(MeshSieveError::ScatterLengthMismatch {
395 expected: total_expected,
396 found,
397 });
398 }
399
400 for &(offset, len) in atlas_map {
401 let end = offset
402 .checked_add(len)
403 .ok_or(MeshSieveError::ScatterChunkMismatch { offset, len })?;
404 if end > self.data.len() {
405 return Err(MeshSieveError::ScatterChunkMismatch { offset, len });
406 }
407 }
408
409 let mut start = 0usize;
410 for &(offset, len) in atlas_map {
411 let end = start + len;
412 let chunk = other
413 .get(start..end)
414 .ok_or(MeshSieveError::ScatterChunkMismatch { offset: start, len })?;
415 let dest = &mut self.data.as_mut_slice()[offset..offset + len];
416 dest.clone_from_slice(chunk);
417 start = end;
418 }
419
420 crate::topology::cache::InvalidateCache::invalidate_cache(self);
421 #[cfg(any(
422 debug_assertions,
423 feature = "strict-invariants",
424 feature = "check-invariants"
425 ))]
426 self.debug_assert_invariants();
427 Ok(())
428 }
429
430 pub fn try_scatter_with_plan(
438 &mut self,
439 buf: &[V],
440 plan: &ScatterPlan,
441 ) -> Result<(), MeshSieveError> {
442 let cur = self.atlas.version();
443 if plan.atlas_version != cur {
444 return Err(MeshSieveError::AtlasPlanStale {
445 expected: plan.atlas_version,
446 found: cur,
447 });
448 }
449 self.try_scatter_from(buf, &plan.spans)
450 }
451}
452
453impl<V: Clone + Default, S: Storage<V> + Clone> Section<V, S> {
454 pub fn new(atlas: Atlas) -> Self {
465 let data = S::with_len(atlas.total_len(), V::default());
466 Section {
467 atlas,
468 data,
469 _marker: PhantomData,
470 }
471 }
472
473 pub fn try_add_point(&mut self, p: PointId, len: usize) -> Result<(), MeshSieveError> {
484 self.atlas
485 .try_insert(p, len)
486 .map_err(|e| MeshSieveError::AtlasInsertionFailed(p, Box::new(e)))?;
487 let new_total = self.atlas.total_len();
488 let old_total = self.data.len();
489 if new_total > old_total {
490 self.data.resize(new_total, V::default());
491 }
492 crate::topology::cache::InvalidateCache::invalidate_cache(self);
493 #[cfg(any(
494 debug_assertions,
495 feature = "strict-invariants",
496 feature = "check-invariants"
497 ))]
498 self.debug_assert_invariants();
499 Ok(())
500 }
501
502 pub fn with_atlas_mut<F>(&mut self, f: F) -> Result<(), MeshSieveError>
522 where
523 F: FnOnce(&mut Atlas),
524 {
525 let before = self.atlas.clone();
527
528 f(&mut self.atlas);
530
531 #[cfg(any(
533 debug_assertions,
534 feature = "strict-invariants",
535 feature = "check-invariants"
536 ))]
537 self.atlas.debug_assert_invariants();
538
539 let new_points: Vec<_> = self.atlas.points().collect();
541
542 use MeshSieveError::AtlasPointLengthChanged;
544 for &pid in &new_points {
545 if let Some((_, len_old)) = before.get(pid) {
546 let (_, len_new) = self
547 .atlas
548 .get(pid)
549 .expect("pid was just iterated from new atlas");
550 if len_old != len_new {
551 self.atlas = before;
552 return Err(AtlasPointLengthChanged {
553 point: pid,
554 expected: len_old,
555 found: len_new,
556 });
557 }
558 }
559 }
560
561 let total_len_new = self.atlas.total_len();
563 let mut new_data = Vec::with_capacity(total_len_new);
564 let old_buf = self.data.as_slice();
565 for pid in new_points {
566 match before.get(pid) {
567 Some((off, len)) => {
569 let end = off + len;
570 let src = old_buf
571 .get(off..end)
572 .ok_or(MeshSieveError::MissingSectionPoint(pid))?;
573 new_data.extend_from_slice(src);
574 }
575 None => {
577 let (_off_new, len_new) = self
578 .atlas
579 .get(pid)
580 .ok_or(MeshSieveError::MissingAtlasPoint(pid))?;
581 new_data.extend(std::iter::repeat_with(V::default).take(len_new));
582 }
583 }
584 }
585
586 let mut next = S::with_len(total_len_new, V::default());
587 next.as_mut_slice().clone_from_slice(&new_data);
588 self.data = next;
589 crate::topology::cache::InvalidateCache::invalidate_cache(self);
590 #[cfg(any(
591 debug_assertions,
592 feature = "strict-invariants",
593 feature = "check-invariants"
594 ))]
595 self.debug_assert_invariants();
596 Ok(())
597 }
598
599 pub fn with_atlas_resize<F>(
606 &mut self,
607 policy: ResizePolicy<V>,
608 f: F,
609 ) -> Result<(), MeshSieveError>
610 where
611 F: FnOnce(&mut Atlas),
612 {
613 let before_atlas = self.atlas.clone();
614 let before_data = self.data.clone();
615
616 f(&mut self.atlas);
617
618 #[cfg(any(
619 debug_assertions,
620 feature = "strict-invariants",
621 feature = "check-invariants"
622 ))]
623 self.atlas.debug_assert_invariants();
624
625 let rebuild = (|| -> Result<Vec<V>, MeshSieveError> {
626 let mut new_data = Vec::with_capacity(self.atlas.total_len());
627 let extend_fill = |buf: &mut Vec<V>, n: usize| match &policy {
628 ResizePolicy::ZeroInit
629 | ResizePolicy::PreservePrefix
630 | ResizePolicy::PreserveSuffix => {
631 buf.extend(std::iter::repeat_with(V::default).take(n));
632 }
633 ResizePolicy::PadWith(val) => {
634 buf.extend(std::iter::repeat_n(val.clone(), n));
635 }
636 };
637 let before_slice = before_data.as_slice();
638 for pid in self.atlas.points() {
639 let (_off_new, new_len) = self
640 .atlas
641 .get(pid)
642 .ok_or(MeshSieveError::MissingAtlasPoint(pid))?;
643 if let Some((off_old, old_len)) = before_atlas.get(pid) {
644 let src = before_slice
645 .get(off_old..off_old + old_len)
646 .ok_or(MeshSieveError::MissingSectionPoint(pid))?;
647 match &policy {
648 ResizePolicy::ZeroInit => {
649 extend_fill(&mut new_data, new_len);
650 }
651 ResizePolicy::PadWith(_) => {
652 extend_fill(&mut new_data, new_len);
653 }
654 ResizePolicy::PreservePrefix => {
655 let k = core::cmp::min(old_len, new_len);
656 new_data.extend_from_slice(&src[..k]);
657 if new_len > k {
658 extend_fill(&mut new_data, new_len - k);
659 }
660 }
661 ResizePolicy::PreserveSuffix => {
662 let k = core::cmp::min(old_len, new_len);
663 if new_len > k {
664 extend_fill(&mut new_data, new_len - k);
665 }
666 new_data.extend_from_slice(&src[old_len - k..]);
667 }
668 }
669 } else {
670 extend_fill(&mut new_data, new_len);
671 }
672 }
673
674 Ok(new_data)
675 })();
676
677 match rebuild {
678 Ok(new_data) => {
679 let mut next = S::with_len(self.atlas.total_len(), V::default());
680 next.as_mut_slice().clone_from_slice(&new_data);
681 self.data = next;
682 crate::topology::cache::InvalidateCache::invalidate_cache(self);
683 #[cfg(any(
684 debug_assertions,
685 feature = "strict-invariants",
686 feature = "check-invariants"
687 ))]
688 self.debug_assert_invariants();
689 Ok(())
690 }
691 Err(e) => {
692 self.atlas = before_atlas;
693 self.data = before_data;
694 Err(e)
695 }
696 }
697 }
698
699 pub fn try_scatter_in_order(&mut self, buf: &[V]) -> Result<(), MeshSieveError> {
707 #[cfg(any(
708 debug_assertions,
709 feature = "strict-invariants",
710 feature = "check-invariants"
711 ))]
712 self.debug_assert_invariants();
713 let spans = self.atlas.atlas_map();
714 self.try_scatter_from(buf, &spans)
715 }
716}
717
718pub trait FallibleMap<V> {
720 fn try_get(&self, p: PointId) -> Result<&[V], MeshSieveError>;
722 fn try_get_mut(&mut self, p: PointId) -> Result<&mut [V], MeshSieveError>;
724}
725
726impl<V, S> FallibleMap<V> for Section<V, S>
728where
729 S: Storage<V>,
730{
731 #[inline]
732 fn try_get(&self, p: PointId) -> Result<&[V], MeshSieveError> {
733 self.try_restrict(p)
734 }
735
736 #[inline]
737 fn try_get_mut(&mut self, p: PointId) -> Result<&mut [V], MeshSieveError> {
738 self.try_restrict_mut(p)
739 }
740}
741
742#[cfg(feature = "map-adapter")]
743#[cfg(feature = "map-adapter")]
748mod sealed {
749 pub trait Sealed {}
750 impl<V, S: crate::data::storage::Storage<V>> Sealed for super::Section<V, S> {}
751 impl<'a, V, S: crate::data::storage::Storage<V>> Sealed
752 for crate::data::refine::helpers::ReadOnlyMap<'a, V, S>
753 {
754 }
755}
756
757#[cfg(feature = "map-adapter")]
763#[cfg_attr(docsrs, doc(cfg(feature = "map-adapter")))]
764pub trait Map<V>: sealed::Sealed {
765 fn get(&self, p: PointId) -> &[V];
767
768 fn get_mut(&mut self, _p: PointId) -> Option<&mut [V]> {
772 None
773 }
774}
775
776#[cfg(feature = "map-adapter")]
777impl<V, S> Map<V> for Section<V, S>
778where
779 S: Storage<V>,
780{
781 #[inline]
782 fn get(&self, p: PointId) -> &[V] {
783 self.try_restrict(p)
784 .unwrap_or_else(|e| panic!("Map::get({p:?}) failed: {e}"))
785 }
786
787 #[inline]
788 fn get_mut(&mut self, p: PointId) -> Option<&mut [V]> {
789 Some(
790 self.try_restrict_mut(p)
791 .unwrap_or_else(|e| panic!("Map::get_mut({p:?}) failed: {e}")),
792 )
793 }
794}
795
796impl<V, S> DebugInvariants for Section<V, S>
797where
798 S: Storage<V>,
799{
800 fn debug_assert_invariants(&self) {
801 crate::debug_invariants!(self.validate_invariants(), "Section invalid");
802 }
803
804 fn validate_invariants(&self) -> Result<(), MeshSieveError> {
805 self.atlas.validate_invariants()?;
807
808 if self.data.len() != self.atlas.total_len() {
809 return Err(MeshSieveError::ScatterLengthMismatch {
810 expected: self.atlas.total_len(),
811 found: self.data.len(),
812 });
813 }
814
815 for (pid, (off, len)) in self.atlas.iter_entries() {
816 let end = off
817 .checked_add(len)
818 .ok_or_else(|| MeshSieveError::ScatterChunkMismatch { offset: off, len })?;
819 if end > self.data.len() {
820 return Err(MeshSieveError::MissingSectionPoint(pid));
821 }
822 }
823
824 Ok(())
825 }
826}
827
828impl<V, S: Storage<V>> InvalidateCache for Section<V, S> {
829 fn invalidate_cache(&mut self) {
830 }
832}
833
834#[cfg(test)]
835mod tests {
836 use super::*;
837 use crate::data::atlas::Atlas;
838 use crate::data::storage::VecStorage;
839 use crate::topology::point::PointId;
840
841 fn make_section() -> Section<f64, VecStorage<f64>> {
842 let mut atlas = Atlas::default();
843 atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap(); atlas.try_insert(PointId::new(2).unwrap(), 1).unwrap();
845 Section::<f64, VecStorage<f64>>::new(atlas)
846 }
847
848 #[test]
849 fn restrict_and_set() {
850 let mut s = make_section();
851 s.try_set(PointId::new(1).unwrap(), &[1.0, 2.0]).unwrap();
852 s.try_set(PointId::new(2).unwrap(), &[3.5]).unwrap();
853
854 assert_eq!(
855 s.try_restrict(PointId::new(1).unwrap()).unwrap(),
856 &[1.0, 2.0]
857 );
858 assert_eq!(s.try_restrict(PointId::new(2).unwrap()).unwrap(), &[3.5]);
859 }
860
861 #[test]
862 fn iter_order() {
863 let mut s = make_section();
864 s.try_set(PointId::new(1).unwrap(), &[9.0, 8.0]).unwrap();
865 s.try_set(PointId::new(2).unwrap(), &[7.0]).unwrap();
866
867 let collected: Vec<_> = s.iter().map(|(_, sl)| sl[0]).collect();
868 assert_eq!(collected, vec![9.0, 7.0]); }
870
871 #[test]
872 fn fallible_map_on_section() {
873 use super::FallibleMap;
874 let mut s = make_section();
875 s.try_set(PointId::new(1).unwrap(), &[1.0, 2.0]).unwrap();
876 assert_eq!(
878 <Section<f64, VecStorage<f64>> as FallibleMap<f64>>::try_get(
879 &s,
880 PointId::new(1).unwrap()
881 )
882 .unwrap(),
883 &[1.0, 2.0]
884 );
885 assert!(
887 <Section<f64, VecStorage<f64>> as FallibleMap<f64>>::try_get(
888 &s,
889 PointId::new(99).unwrap()
890 )
891 .is_err()
892 );
893 assert!(
895 <Section<f64, VecStorage<f64>> as FallibleMap<f64>>::try_get_mut(
896 &mut s,
897 PointId::new(1).unwrap()
898 )
899 .is_ok()
900 );
901 }
902
903 #[cfg(feature = "map-adapter")]
904 #[test]
905 fn map_trait_section_get_and_mut() {
906 use super::Map;
907 let mut s = make_section();
908 s.try_set(PointId::new(1).unwrap(), &[1.0, 2.0]).unwrap();
909 s.try_set(PointId::new(2).unwrap(), &[3.5]).unwrap();
910 assert_eq!(
912 <Section<f64, VecStorage<f64>> as Map<f64>>::get(&s, PointId::new(1).unwrap()),
913 s.try_restrict(PointId::new(1).unwrap()).unwrap()
914 );
915 assert!(
917 <Section<f64, VecStorage<f64>> as Map<f64>>::get_mut(&mut s, PointId::new(1).unwrap())
918 .is_some()
919 );
920 }
921
922 #[test]
923 fn scatter_from() {
924 let mut s = make_section();
925 assert_eq!(s.as_flat_slice(), &[0.0, 0.0, 0.0]);
927
928 let _ = s.try_scatter_from(&[1.0, 2.0, 3.5], &[(0, 2), (2, 1)]);
930
931 assert_eq!(s.as_flat_slice(), &[1.0, 2.0, 3.5]);
933 }
934
935 #[test]
936 fn section_round_trip_and_scatter() {
937 let mut atlas = Atlas::default();
938 atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap();
939 atlas.try_insert(PointId::new(2).unwrap(), 1).unwrap();
940 let mut s = Section::<f64, VecStorage<f64>>::new(atlas.clone());
941 s.try_set(PointId::new(1).unwrap(), &[1.1, 2.2]).unwrap();
943 s.try_set(PointId::new(2).unwrap(), &[3.3]).unwrap();
944 assert_eq!(
945 s.try_restrict(PointId::new(1).unwrap()).unwrap(),
946 &[1.1, 2.2]
947 );
948 assert_eq!(s.try_restrict(PointId::new(2).unwrap()).unwrap(), &[3.3]);
949 let mut s2 = Section::<f64, VecStorage<f64>>::new(atlas);
951 s2.try_scatter_from(&[1.1, 2.2, 3.3], &[(0, 2), (2, 1)])
952 .unwrap();
953 assert_eq!(
954 s2.try_restrict(PointId::new(1).unwrap()).unwrap(),
955 &[1.1, 2.2]
956 );
957 assert_eq!(s2.try_restrict(PointId::new(2).unwrap()).unwrap(), &[3.3]);
958 }
959
960 #[cfg(feature = "map-adapter")]
961 #[test]
962 fn section_map_trait_and_readonly() {
963 use super::Map;
964 let mut atlas = Atlas::default();
965 atlas.try_insert(PointId::new(1).unwrap(), 1).unwrap();
966 let mut s = Section::<i32, VecStorage<i32>>::new(atlas);
967 s.try_set(PointId::new(1).unwrap(), &[42]).unwrap();
968 assert_eq!(
970 <Section<i32, VecStorage<i32>> as Map<i32>>::get(&s, PointId::new(1).unwrap()),
971 &[42]
972 );
973 assert!(
975 <Section<i32, VecStorage<i32>> as Map<i32>>::get_mut(&mut s, PointId::new(1).unwrap())
976 .is_some()
977 );
978 }
979
980 #[test]
981 fn add_point_expands_and_defaults() {
982 let mut atlas = Atlas::default();
983 atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap();
984 let mut s = Section::<i32, VecStorage<i32>>::new(atlas.clone());
985 assert_eq!(s.iter().count(), 1);
987 s.try_add_point(PointId::new(2).unwrap(), 3).unwrap();
989 let mut pts: Vec<_> = s.iter().map(|(p, _)| p).collect();
991 pts.sort_unstable();
992 assert_eq!(
993 pts,
994 vec![PointId::new(1).unwrap(), PointId::new(2).unwrap()]
995 );
996 assert_eq!(
998 s.try_restrict(PointId::new(2).unwrap()).unwrap(),
999 &[0, 0, 0]
1000 );
1001 s.try_set(PointId::new(2).unwrap(), &[7, 8, 9]).unwrap();
1003 assert_eq!(
1004 s.try_restrict(PointId::new(2).unwrap()).unwrap(),
1005 &[7, 8, 9]
1006 );
1007 }
1008
1009 #[test]
1010 fn remove_point_compacts_and_forgets() {
1011 let mut atlas = Atlas::default();
1013 atlas.try_insert(PointId::new(1).unwrap(), 2).unwrap();
1014 atlas.try_insert(PointId::new(2).unwrap(), 1).unwrap();
1015 atlas.try_insert(PointId::new(3).unwrap(), 2).unwrap();
1016 let mut s = Section::<i32, VecStorage<i32>>::new(atlas);
1017 s.try_set(PointId::new(1).unwrap(), &[10, 11]).unwrap();
1019 s.try_set(PointId::new(2).unwrap(), &[22]).unwrap();
1020 s.try_set(PointId::new(3).unwrap(), &[33, 34]).unwrap();
1021 let _ = s.try_remove_point(PointId::new(2).unwrap());
1023 let pts: Vec<_> = s.iter().map(|(p, _)| p).collect();
1025 assert_eq!(
1026 pts,
1027 vec![PointId::new(1).unwrap(), PointId::new(3).unwrap()]
1028 );
1029 let all: Vec<_> = s.as_flat_slice().iter().copied().collect();
1031 assert_eq!(all, vec![10, 11, 33, 34]);
1032 std::panic::catch_unwind(|| {
1034 let _ = s.try_restrict(PointId::new(2).unwrap()).unwrap();
1035 })
1036 .expect_err("should panic");
1037 }
1038
1039 #[test]
1040 #[should_panic(expected = "called `Result::unwrap()` on an `Err` value")]
1041 fn restrict_missing_panics() {
1042 let s = make_section();
1043 let _ = s.try_restrict(PointId::new(99).unwrap()).unwrap();
1044 }
1045
1046 #[test]
1047 fn set_wrong_length_returns_err() {
1048 let mut s = make_section();
1049 let err = s.try_set(PointId::new(1).unwrap(), &[1.0]).unwrap_err();
1050 assert_eq!(
1051 err,
1052 MeshSieveError::SliceLengthMismatch {
1053 point: PointId::new(1).unwrap(),
1054 expected: 2,
1055 found: 1
1056 }
1057 );
1058 }
1059
1060 #[test]
1061 fn invalidate_cache_noop() {
1062 let mut s = make_section();
1063 InvalidateCache::invalidate_cache(&mut s);
1065 }
1066}
1067
1068#[cfg(test)]
1069mod tests_resize {
1070 use super::*;
1071 use crate::data::storage::VecStorage;
1072 use crate::topology::point::PointId;
1073
1074 fn pid(i: u64) -> PointId {
1075 PointId::new(i).unwrap()
1076 }
1077
1078 #[test]
1079 fn strict_with_atlas_mut_rejects_len_change() {
1080 let mut atlas = Atlas::default();
1081 let p = pid(1);
1082 atlas.try_insert(p, 3).unwrap();
1083 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1084
1085 s.try_set(p, &[1, 2, 3]).unwrap();
1086
1087 let err = s
1088 .with_atlas_mut(|a| {
1089 a.remove_point(p).unwrap();
1090 a.try_insert(p, 5).unwrap();
1091 })
1092 .unwrap_err();
1093
1094 match err {
1095 MeshSieveError::AtlasPointLengthChanged {
1096 point,
1097 expected,
1098 found,
1099 } => {
1100 assert_eq!(point, p);
1101 assert_eq!(expected, 3);
1102 assert_eq!(found, 5);
1103 }
1104 e => panic!("unexpected error: {e:?}"),
1105 }
1106
1107 assert_eq!(s.atlas().get(p).unwrap().1, 3);
1108 assert_eq!(s.try_restrict(p).unwrap(), &[1, 2, 3]);
1109 }
1110
1111 #[test]
1112 fn resize_preserve_prefix_and_zero_extend() {
1113 let mut atlas = Atlas::default();
1114 let p = pid(1);
1115 atlas.try_insert(p, 3).unwrap();
1116 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1117 s.try_set(p, &[10, 20, 30]).unwrap();
1118
1119 s.with_atlas_resize(ResizePolicy::PreservePrefix, |a| {
1120 a.remove_point(p).unwrap();
1121 a.try_insert(p, 5).unwrap();
1122 })
1123 .unwrap();
1124
1125 assert_eq!(s.try_restrict(p).unwrap(), &[10, 20, 30, 0, 0]);
1126 }
1127
1128 #[test]
1129 fn resize_preserve_suffix_and_zero_prepad() {
1130 let mut atlas = Atlas::default();
1131 let p = pid(1);
1132 atlas.try_insert(p, 3).unwrap();
1133 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1134 s.try_set(p, &[10, 20, 30]).unwrap();
1135
1136 s.with_atlas_resize(ResizePolicy::PreserveSuffix, |a| {
1137 a.remove_point(p).unwrap();
1138 a.try_insert(p, 5).unwrap();
1139 })
1140 .unwrap();
1141
1142 assert_eq!(s.try_restrict(p).unwrap(), &[0, 0, 10, 20, 30]);
1143 }
1144
1145 #[test]
1146 fn resize_pad_with_custom_value() {
1147 let mut atlas = Atlas::default();
1148 let p = pid(1);
1149 atlas.try_insert(p, 2).unwrap();
1150 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1151 s.try_set(p, &[7, 9]).unwrap();
1152
1153 s.with_atlas_resize(ResizePolicy::PadWith(-1), |a| {
1154 a.remove_point(p).unwrap();
1155 a.try_insert(p, 4).unwrap();
1156 })
1157 .unwrap();
1158
1159 assert_eq!(s.try_restrict(p).unwrap(), &[-1, -1, -1, -1]);
1160 }
1161
1162 #[test]
1163 fn resize_shrink_preserve_prefix() {
1164 let mut atlas = Atlas::default();
1165 let p = pid(1);
1166 atlas.try_insert(p, 4).unwrap();
1167 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1168 s.try_set(p, &[1, 2, 3, 4]).unwrap();
1169
1170 s.with_atlas_resize(ResizePolicy::PreservePrefix, |a| {
1171 a.remove_point(p).unwrap();
1172 a.try_insert(p, 2).unwrap();
1173 })
1174 .unwrap();
1175
1176 assert_eq!(s.try_restrict(p).unwrap(), &[1, 2]);
1177 }
1178
1179 #[test]
1180 fn resize_shrink_preserve_suffix() {
1181 let mut atlas = Atlas::default();
1182 let p = pid(1);
1183 atlas.try_insert(p, 4).unwrap();
1184 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1185 s.try_set(p, &[1, 2, 3, 4]).unwrap();
1186
1187 s.with_atlas_resize(ResizePolicy::PreserveSuffix, |a| {
1188 a.remove_point(p).unwrap();
1189 a.try_insert(p, 2).unwrap();
1190 })
1191 .unwrap();
1192
1193 assert_eq!(s.try_restrict(p).unwrap(), &[3, 4]);
1194 }
1195}
1196
1197#[cfg(test)]
1198mod tests_invariants_precheck {
1199 use super::*;
1200 use crate::data::atlas::Atlas;
1201 use crate::data::storage::VecStorage;
1202 use crate::topology::point::PointId;
1203
1204 #[cfg(not(debug_assertions))]
1205 use crate::{mesh_error::MeshSieveError, topology::arrow::Polarity};
1206
1207 fn pid(i: u64) -> PointId {
1208 PointId::new(i).unwrap()
1209 }
1210
1211 #[test]
1212 #[cfg(not(debug_assertions))]
1213 fn delta_returns_missing_point_in_release_paths() {
1214 let mut atlas = Atlas::default();
1215 let p0 = pid(1);
1216 let p1 = pid(2);
1217 atlas.try_insert(p0, 2).unwrap();
1218 atlas.try_insert(p1, 2).unwrap();
1219 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1220
1221 let mut bad = s.atlas.clone();
1222 bad.remove_point(p1).unwrap();
1223 let dummy = pid(99);
1224 bad.try_insert(dummy, s.as_flat_slice().len() + 8).unwrap();
1225 bad.try_insert(p1, 2).unwrap();
1226 s.atlas = bad;
1227
1228 let e = s
1229 .try_apply_delta_between_points(p0, p1, &Polarity::Forward)
1230 .unwrap_err();
1231
1232 match e {
1233 MeshSieveError::MissingSectionPoint(q) => assert_eq!(q, p1),
1234 _ => panic!("unexpected error: {e:?}"),
1235 }
1236 }
1237
1238 #[test]
1239 fn for_each_in_order_prechecks_in_debug() {
1240 let mut atlas = Atlas::default();
1241 let p = pid(7);
1242 atlas.try_insert(p, 1).unwrap();
1243 let mut s: Section<i32, VecStorage<i32>> = Section::new(atlas);
1244
1245 s.data.resize(0, 0);
1246
1247 #[cfg(any(
1248 debug_assertions,
1249 feature = "strict-invariants",
1250 feature = "check-invariants"
1251 ))]
1252 {
1253 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1254 s.for_each_in_order(|_, _| {});
1255 }));
1256 assert!(result.is_err(), "expected invariant pre-check to panic");
1257 }
1258 }
1259}
1260
1261pub use crate::data::refine::Sifter;