1use alloc::{boxed::Box, string::String, vec::Vec};
9use core::{borrow::Borrow, fmt, ops::Deref};
10
11use buggy::{Bug, BugExt as _};
12use rend::u64_le;
13
14use crate::{Address, CmdId, Command, PolicyId, Prior};
15
16pub mod linear;
17
18#[cfg(any(feature = "libc", feature = "testing"))]
19mod spill;
20#[cfg(feature = "libc")]
21pub use spill::LibcSpill;
22#[cfg(feature = "testing")]
23pub use spill::MemSpill;
24
25pub trait Spill {
32 fn write_at(&mut self, offset: usize, data: &[u8]) -> Result<(), StorageError>;
34 fn read_at(&mut self, offset: usize, data: &mut [u8]) -> Result<(), StorageError>;
36}
37
38pub const QUEUE_CAPACITY: usize = 512;
43
44#[derive(Debug, Default)]
54pub struct TraversalQueue {
55 entries: heapless::Vec<Location, QUEUE_CAPACITY>,
56 partition: usize,
58}
59
60impl TraversalQueue {
61 pub const fn new() -> Self {
63 Self {
64 entries: heapless::Vec::new(),
65 partition: 0,
66 }
67 }
68
69 pub fn clear(&mut self) {
71 self.entries.clear();
72 self.partition = 0;
73 }
74
75 pub fn is_empty(&self) -> bool {
77 self.entries.is_empty()
78 }
79
80 pub fn push(&mut self, loc: Location) -> Result<(), StorageError> {
85 self.push_covered(loc, false)
86 }
87
88 pub fn push_covered(&mut self, loc: Location, covered: bool) -> Result<(), StorageError> {
95 if let Some(i) = self.entries.iter().position(|x| x.same_segment(loc)) {
96 let was_covered = i >= self.partition;
97 let new_covered = if loc.max_cut > self.entries[i].max_cut {
98 self.entries[i].max_cut = loc.max_cut;
99 covered
100 } else if loc.max_cut == self.entries[i].max_cut {
101 was_covered || covered
102 } else {
103 return Ok(());
104 };
105 if !was_covered && new_covered {
106 self.partition = self
107 .partition
108 .checked_sub(1)
109 .assume("partition must be >= 1 when uncovered entry exists")?;
110 self.entries.swap(i, self.partition);
111 } else if was_covered && !new_covered {
112 self.entries.swap(i, self.partition);
113 self.partition = self
114 .partition
115 .checked_add(1)
116 .assume("partition must not overflow")?;
117 }
118 return Ok(());
119 }
120 self.entries
121 .push(loc)
122 .map_err(|_| StorageError::TraversalQueueOverflow(QUEUE_CAPACITY))?;
123 if !covered {
124 let last = self
125 .entries
126 .len()
127 .checked_sub(1)
128 .assume("just pushed, len must be >= 1")?;
129 self.entries.swap(self.partition, last);
130 self.partition = self
131 .partition
132 .checked_add(1)
133 .assume("partition must not overflow")?;
134 }
135 Ok(())
136 }
137
138 pub fn push_duplicate(&mut self, loc: Location) -> Result<(), StorageError> {
144 self.entries
145 .push(loc)
146 .map_err(|_| StorageError::TraversalQueueOverflow(QUEUE_CAPACITY))?;
147 let last = self
149 .entries
150 .len()
151 .checked_sub(1)
152 .assume("just pushed, len must be >= 1")?;
153 self.entries.swap(self.partition, last);
154 self.partition = self
155 .partition
156 .checked_add(1)
157 .assume("partition must not overflow")?;
158 Ok(())
159 }
160
161 pub fn pop(&mut self) -> Result<Option<Location>, StorageError> {
163 Ok(self.pop_covered()?.map(|(loc, _)| loc))
164 }
165
166 pub fn pop_covered(&mut self) -> Result<Option<(Location, bool)>, StorageError> {
168 let Some((i, _)) = self.entries.iter().enumerate().max_by_key(|&(_, loc)| *loc) else {
169 return Ok(None);
170 };
171 if i < self.partition {
172 Ok(Some((self.remove_uncovered(i)?, false)))
173 } else {
174 let loc = self.entries.swap_remove(i);
176 Ok(Some((loc, true)))
177 }
178 }
179
180 fn remove_uncovered(&mut self, i: usize) -> Result<Location, StorageError> {
183 self.partition = self
184 .partition
185 .checked_sub(1)
186 .assume("partition must be >= 1 when uncovered entry exists")?;
187 self.entries.swap(i, self.partition);
188 Ok(self.entries.swap_remove(self.partition))
189 }
190
191 pub fn peek(&self) -> Option<&Location> {
193 self.entries.iter().max_by_key(|loc| *loc)
194 }
195
196 pub fn pop_duplicates(&mut self) -> Result<Option<(Location, usize)>, StorageError> {
202 let Some(location) = self.entries.iter().max_by_key(|loc| *loc).copied() else {
203 return Ok(None);
204 };
205
206 let mut count: usize = 0;
209 let mut j = self.entries.len();
210 while j > 0 {
211 j = j.checked_sub(1).assume("j > 0 checked in loop condition")?;
212 if self.entries[j] == location {
213 count = count
214 .checked_add(1)
215 .assume("count bounded by QUEUE_CAPACITY")?;
216 if j < self.partition {
217 self.partition = self
218 .partition
219 .checked_sub(1)
220 .assume("partition >= 1 when uncovered entry at j < partition")?;
221 self.entries.swap(j, self.partition);
222 self.entries.swap_remove(self.partition);
223 } else {
224 self.entries.swap_remove(j);
225 }
226 }
227 }
228
229 Ok(Some((location, count)))
230 }
231
232 pub fn all_covered(&self) -> bool {
234 self.partition == 0
235 }
236
237 pub fn drain_above(
242 &mut self,
243 threshold: MaxCut,
244 mut f: impl FnMut(Location),
245 ) -> Result<(), StorageError> {
246 let mut i = 0;
248 while i < self.partition {
249 if self.entries[i].max_cut > threshold {
250 f(self.remove_uncovered(i)?);
251 } else {
252 i = i.checked_add(1).assume("index must not overflow")?;
253 }
254 }
255 let mut i = self.partition;
258 while i < self.entries.len() {
259 if self.entries[i].max_cut > threshold {
260 self.entries.swap_remove(i);
261 } else {
262 i = i.checked_add(1).assume("index must not overflow")?;
263 }
264 }
265 Ok(())
266 }
267
268 pub fn cover_up_to(
276 &mut self,
277 segment: SegmentIndex,
278 coverage_mc: MaxCut,
279 longest_mc: MaxCut,
280 ) -> Result<(), StorageError> {
281 let Some(i) = self.entries.iter().position(|x| x.segment == segment) else {
282 return Ok(());
283 };
284 let was_covered = i >= self.partition;
285 if was_covered {
286 return Ok(());
287 }
288 if coverage_mc >= longest_mc {
289 self.partition = self
291 .partition
292 .checked_sub(1)
293 .assume("partition must be >= 1 when uncovered entry exists")?;
294 self.entries.swap(i, self.partition);
295 } else if coverage_mc >= self.entries[i].max_cut {
296 self.entries[i].max_cut = coverage_mc
298 .checked_add(1)
299 .assume("coverage_mc + 1 must not overflow")?;
300 }
301 Ok(())
303 }
304
305 pub fn drain_all(&mut self, mut f: impl FnMut(Location)) {
308 for i in 0..self.partition {
309 f(self.entries[i]);
310 }
311 self.entries.clear();
312 self.partition = 0;
313 }
314}
315
316pub struct TraversalBuffer {
320 queue: TraversalQueue,
321}
322
323impl TraversalBuffer {
324 pub const fn new() -> Self {
325 Self {
326 queue: TraversalQueue::new(),
327 }
328 }
329
330 pub fn get(&mut self) -> &mut TraversalQueue {
332 self.queue.clear();
333 &mut self.queue
334 }
335}
336
337impl Default for TraversalBuffer {
338 fn default() -> Self {
339 Self::new()
340 }
341}
342
343pub struct TraversalBuffers {
349 pub primary: TraversalBuffer,
350 pub secondary: TraversalBuffer,
351}
352
353impl TraversalBuffers {
354 pub const fn new() -> Self {
355 Self {
356 primary: TraversalBuffer::new(),
357 secondary: TraversalBuffer::new(),
358 }
359 }
360}
361
362impl Default for TraversalBuffers {
363 fn default() -> Self {
364 Self::new()
365 }
366}
367
368#[cfg(feature = "low-mem-usage")]
369pub const MAX_COMMAND_LENGTH: usize = 400;
370#[cfg(not(feature = "low-mem-usage"))]
371pub const MAX_COMMAND_LENGTH: usize = 2048;
372
373aranya_crypto::custom_id! {
374 pub struct GraphId;
376}
377
378#[derive(
379 Copy,
380 Clone,
381 Debug,
382 Hash,
383 PartialEq,
384 Eq,
385 PartialOrd,
386 Ord,
387 serde::Serialize,
388 serde::Deserialize,
389 rkyv::Archive,
390 rkyv::Serialize,
391 rkyv::Deserialize,
392 rkyv::Portable,
393 rkyv::bytecheck::CheckBytes,
394 zerocopy::IntoBytes,
395 zerocopy::FromBytes,
396 zerocopy::Immutable,
397 zerocopy::KnownLayout,
398)]
399#[rkyv(as = Self)]
400#[bytecheck(crate = rkyv::bytecheck)]
401#[serde(transparent)]
402#[repr(transparent)]
403pub struct SegmentIndex(#[serde(with = "crate::util::u64_le_serde")] u64_le);
404
405impl fmt::Display for SegmentIndex {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 fmt::Display::fmt(&self.0, f)
408 }
409}
410
411impl SegmentIndex {
412 pub const fn new(val: u64) -> Self {
413 Self(u64_le::from_native(val))
414 }
415
416 pub const fn get(self) -> u64 {
417 self.0.to_native()
418 }
419}
420
421#[derive(
422 Copy,
423 Clone,
424 Debug,
425 Hash,
426 PartialEq,
427 Eq,
428 PartialOrd,
429 Ord,
430 serde::Serialize,
431 serde::Deserialize,
432 rkyv::Archive,
433 rkyv::Serialize,
434 rkyv::Deserialize,
435 rkyv::Portable,
436 rkyv::bytecheck::CheckBytes,
437 zerocopy::IntoBytes,
438 zerocopy::FromBytes,
439 zerocopy::Immutable,
440 zerocopy::KnownLayout,
441)]
442#[rkyv(as = Self)]
443#[bytecheck(crate = rkyv::bytecheck)]
444#[serde(transparent)]
445#[repr(transparent)]
446pub struct MaxCut(#[serde(with = "crate::util::u64_le_serde")] u64_le);
447
448impl fmt::Display for MaxCut {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 fmt::Display::fmt(&self.0, f)
451 }
452}
453
454impl MaxCut {
455 pub const fn new(val: u64) -> Self {
456 Self(u64_le::from_native(val))
457 }
458
459 pub const fn get(self) -> u64 {
460 self.0.to_native()
461 }
462
463 #[must_use]
465 pub fn checked_add(self, other: u64) -> Option<Self> {
466 self.get().checked_add(other).map(Self::new)
467 }
468
469 #[must_use]
471 pub fn decremented(self) -> Option<Self> {
472 self.get().checked_sub(1).map(Self::new)
473 }
474
475 #[must_use]
477 pub fn distance_from(self, other: Self) -> Option<u64> {
478 self.get().checked_sub(other.get())
479 }
480}
481
482#[derive(
483 Copy,
484 Clone,
485 Debug,
486 Hash,
487 PartialEq,
488 Eq,
489 PartialOrd,
490 Ord,
491 serde::Serialize,
492 serde::Deserialize,
493 rkyv::Archive,
494 rkyv::Serialize,
495 rkyv::Deserialize,
496 rkyv::Portable,
497 rkyv::bytecheck::CheckBytes,
498 zerocopy::IntoBytes,
499 zerocopy::FromBytes,
500 zerocopy::Immutable,
501 zerocopy::KnownLayout,
502)]
503#[rkyv(as = Self)]
504#[bytecheck(crate = rkyv::bytecheck)]
505#[repr(C)]
506pub struct Location {
507 pub max_cut: MaxCut,
508 pub segment: SegmentIndex,
509}
510
511impl From<(SegmentIndex, MaxCut)> for Location {
512 fn from((segment, max_cut): (SegmentIndex, MaxCut)) -> Self {
513 Self::new(segment, max_cut)
514 }
515}
516
517impl AsRef<Self> for Location {
518 fn as_ref(&self) -> &Self {
519 self
520 }
521}
522
523impl Location {
524 pub fn new(segment: SegmentIndex, max_cut: MaxCut) -> Self {
525 Self { max_cut, segment }
526 }
527
528 pub fn same_segment(self, other: Self) -> bool {
530 self.segment == other.segment
531 }
532}
533
534impl fmt::Display for Location {
535 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536 write!(f, "{}:{}", self.segment, self.max_cut)
537 }
538}
539
540#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
541pub struct LocatedAddress {
542 pub id: CmdId,
543 pub segment: SegmentIndex,
544 pub max_cut: MaxCut,
545}
546
547impl LocatedAddress {
548 pub fn address(self) -> Address {
549 Address {
550 id: self.id,
551 max_cut: self.max_cut,
552 }
553 }
554
555 pub fn location(self) -> Location {
556 Location {
557 segment: self.segment,
558 max_cut: self.max_cut,
559 }
560 }
561}
562
563#[derive(Debug, thiserror::Error)]
565#[cfg_attr(test, derive(PartialEq, Eq))]
566#[non_exhaustive]
567pub enum StorageError {
568 #[error("storage already exists")]
569 StorageExists,
570 #[error("no such storage")]
571 NoSuchStorage,
572 #[error("segment index {} is out of bounds", .0.segment)]
573 SegmentOutOfBounds(Location),
574 #[error("max cut {} is out of bounds in segment {}", .0.max_cut, .0.segment)]
575 CommandOutOfBounds(Location),
576 #[error("IO error")]
577 IoError,
578 #[error("policy mismatch")]
579 PolicyMismatch,
580 #[error("cannot write an empty perspective")]
581 EmptyPerspective,
582 #[error("traversal queue overflow (capacity {0})")]
583 TraversalQueueOverflow(usize),
584 #[error("strand heap overflow (capacity {0})")]
585 StrandHeapOverflow(usize),
586 #[error("convergence root index overflow (capacity {0})")]
587 ConvergenceRootOverflow(usize),
588 #[error("command's parents do not match the perspective head")]
589 PerspectiveHeadMismatch,
590 #[error(transparent)]
591 Bug(#[from] Bug),
592}
593
594pub trait StorageProvider {
596 type Perspective: Perspective + Revertable;
597 type Segment: Segment;
598 type Storage: Storage<
599 Segment = Self::Segment,
600 Perspective = Self::Perspective,
601 FactIndex = <Self::Segment as Segment>::FactIndex,
602 >;
603
604 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective;
610
611 fn new_storage(
618 &mut self,
619 init: Self::Perspective,
620 ) -> Result<(GraphId, &mut Self::Storage), StorageError>;
621
622 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError>;
628
629 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError>;
635
636 fn list_graph_ids(
639 &mut self,
640 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError>;
641}
642
643pub trait Storage {
646 type Perspective: Perspective + Revertable;
647 type FactPerspective: FactPerspective;
648 type Segment: Segment<FactIndex = Self::FactIndex>;
649 type FactIndex: FactIndex;
650
651 fn get_location(
654 &self,
655 address: Address,
656 buffer: &mut TraversalBuffer,
657 ) -> Result<Option<Location>, StorageError> {
658 self.get_location_from(self.get_head()?, address, buffer)
659 }
660
661 fn get_location_from(
665 &self,
666 start: Location,
667 address: Address,
668 buffer: &mut TraversalBuffer,
669 ) -> Result<Option<Location>, StorageError> {
670 if start.max_cut < address.max_cut {
671 return Ok(None);
672 }
673
674 let queue = buffer.get();
675 queue.push(start)?;
676
677 while let Some(loc) = queue.pop()? {
678 debug_assert!(
679 loc.max_cut >= address.max_cut,
680 "Invariant: we only enqueue locations with at least the target max cut"
681 );
682
683 let segment = self.get_segment(loc)?;
685
686 if let Some(found) = segment.get_by_address(address) {
688 return Ok(Some(found));
689 }
690
691 if let Some(&skip) = segment
696 .skip_list()
697 .iter()
698 .find(|skip| skip.max_cut >= address.max_cut)
699 {
700 queue.push(skip)?;
701 } else {
702 for prior in segment.prior() {
704 if prior.max_cut >= address.max_cut {
705 queue.push(prior)?;
706 }
707 }
708 }
709 }
710 Ok(None)
711 }
712
713 fn get_command_address(&self, location: Location) -> Result<Address, StorageError> {
717 let segment = self.get_segment(location)?;
718 let command = segment
719 .get_command(location)
720 .ok_or(StorageError::CommandOutOfBounds(location))?;
721 let address = command.address()?;
722 Ok(address)
723 }
724
725 fn get_linear_perspective(&self, parent: Location) -> Result<Self::Perspective, StorageError>;
727
728 fn get_fact_perspective(&self, first: Location) -> Result<Self::FactPerspective, StorageError>;
731
732 fn new_merge_perspective(
734 &self,
735 left: Location,
736 right: Location,
737 last_common_ancestor: Location,
738 policy_id: PolicyId,
739 braid: Self::FactIndex,
740 ) -> Result<Self::Perspective, StorageError>;
741
742 fn get_segment(&self, location: Location) -> Result<Self::Segment, StorageError>;
744
745 fn get_head(&self) -> Result<Location, StorageError>;
747
748 fn get_head_address(&self) -> Result<Address, StorageError> {
750 self.get_command_address(self.get_head()?)
751 }
752
753 fn commit(&mut self, segment: Self::Segment) -> Result<(), StorageError>;
758
759 fn write(&mut self, perspective: Self::Perspective) -> Result<Self::Segment, StorageError>;
761
762 fn write_facts(
764 &mut self,
765 fact_perspective: Self::FactPerspective,
766 ) -> Result<Self::FactIndex, StorageError>;
767
768 fn is_ancestor(
770 &self,
771 search_location: Location,
772 start_location: Location,
773 buffer: &mut TraversalBuffer,
774 ) -> Result<bool, StorageError> {
775 if search_location.max_cut > start_location.max_cut || search_location == start_location {
776 return Ok(false);
777 }
778
779 let queue = buffer.get();
780 queue.push(start_location)?;
781
782 while let Some(loc) = queue.pop()? {
783 debug_assert!(
784 loc.max_cut >= search_location.max_cut,
785 "Invariant: we only enqueue locations with at least the target max cut"
786 );
787
788 let segment = self.get_segment(loc)?;
790
791 if segment.get_command(search_location).is_some() {
793 return Ok(true);
794 }
795
796 if let Some(&skip) = segment
801 .skip_list()
802 .iter()
803 .find(|skip| skip.max_cut >= search_location.max_cut)
804 {
805 queue.push(skip)?;
806 } else {
807 for prior in segment.prior() {
809 if prior.max_cut >= search_location.max_cut {
810 queue.push(prior)?;
811 }
812 }
813 }
814 }
815 Ok(false)
816 }
817}
818
819pub trait Segment {
829 type FactIndex: FactIndex;
830 type Command<'a>: Command
831 where
832 Self: 'a;
833
834 fn index(&self) -> SegmentIndex;
836
837 fn head_id(&self) -> CmdId;
839
840 fn policy(&self) -> PolicyId;
842
843 fn prior(&self) -> Prior<Location>;
845
846 fn get_command(&self, location: Location) -> Option<Self::Command<'_>>;
848
849 fn facts(&self) -> Result<Self::FactIndex, StorageError>;
851
852 fn shortest_max_cut(&self) -> MaxCut;
856
857 fn longest_max_cut(&self) -> Result<MaxCut, StorageError>;
861
862 fn skip_list(&self) -> &[Location];
871
872 fn get_from(&self, location: Location) -> Vec<Self::Command<'_>> {
874 let segment = location.segment;
875 core::iter::successors(Some(location.max_cut), |max_cut| max_cut.checked_add(1))
876 .map_while(|max_cut| self.get_command(Location { max_cut, segment }))
877 .collect()
878 }
879
880 fn get_by_address(&self, address: Address) -> Option<Location> {
882 let loc = Location::new(self.index(), address.max_cut);
883 let cmd = self.get_command(loc)?;
884 if cmd.id() != address.id {
885 return None;
886 }
887 Some(loc)
888 }
889
890 fn first_location(&self) -> Location {
892 Location {
893 max_cut: self.shortest_max_cut(),
894 segment: self.index(),
895 }
896 }
897
898 fn head_location(&self) -> Result<Location, StorageError> {
900 Ok(Location {
901 max_cut: self.longest_max_cut()?,
902 segment: self.index(),
903 })
904 }
905
906 fn head_address(&self) -> Result<Address, StorageError> {
908 Ok(Address {
909 id: self.head_id(),
910 max_cut: self.longest_max_cut()?,
911 })
912 }
913
914 #[must_use]
916 fn previous(&self, mut location: Location) -> Option<Location> {
917 debug_assert_eq!(location.segment, self.index());
918 if location.max_cut <= self.shortest_max_cut() {
919 return None;
920 }
921 location.max_cut = location.max_cut.decremented()?;
922 Some(location)
923 }
924}
925
926pub trait FactIndex: Query {}
928
929pub trait Perspective: FactPerspective {
932 fn policy(&self) -> PolicyId;
934
935 fn add_command(&mut self, command: &impl Command) -> Result<usize, StorageError>;
938
939 fn includes(&self, id: CmdId) -> bool;
941
942 fn head_address(&self) -> Result<Prior<Address>, Bug>;
944}
945
946pub trait FactPerspective: QueryMut {}
948
949pub trait Revertable {
952 fn checkpoint(&self) -> Checkpoint;
954
955 fn revert(&mut self, checkpoint: Checkpoint) -> Result<(), StorageError>;
957}
958
959pub struct Checkpoint {
961 pub index: usize,
963}
964
965pub trait Query {
972 fn query(&self, name: &str, keys: &[Bytes]) -> Result<Option<Bytes>, StorageError>;
974
975 type QueryIterator: Iterator<Item = Result<Fact, StorageError>>;
977
978 fn query_prefix(
983 &self,
984 name: &str,
985 prefix: &[Bytes],
986 ) -> Result<Self::QueryIterator, StorageError>;
987}
988
989#[derive(Debug, PartialEq, Eq)]
991pub struct Fact {
992 pub key: Keys,
994 pub value: Bytes,
996}
997
998pub trait QueryMut: Query {
1002 fn insert(&mut self, name: String, keys: Keys, value: Bytes) -> Result<(), StorageError>;
1006
1007 fn delete(&mut self, name: String, keys: Keys) -> Result<(), StorageError>;
1009}
1010
1011#[cfg(all(test, feature = "graphviz"))]
1013pub(crate) trait FactIndexExtra {
1014 fn name(&self) -> String;
1015 fn prior(&self) -> Result<Option<Self>, StorageError>
1016 where
1017 Self: Sized;
1018}
1019
1020#[derive(
1022 Clone,
1023 Debug,
1024 Default,
1025 PartialEq,
1026 Eq,
1027 PartialOrd,
1028 Ord,
1029 serde::Serialize,
1030 serde::Deserialize,
1031 rkyv::Archive,
1032 rkyv::Serialize,
1033 rkyv::Deserialize,
1034)]
1035pub struct Keys(Box<[Bytes]>);
1036
1037impl Deref for Keys {
1038 type Target = [Bytes];
1039 fn deref(&self) -> &[Bytes] {
1040 self.0.as_ref()
1041 }
1042}
1043
1044impl AsRef<[Bytes]> for Keys {
1045 fn as_ref(&self) -> &[Bytes] {
1046 self.0.as_ref()
1047 }
1048}
1049
1050impl Borrow<[Bytes]> for Keys {
1051 fn borrow(&self) -> &[Bytes] {
1052 self.0.as_ref()
1053 }
1054}
1055
1056impl From<Vec<Bytes>> for Keys {
1057 fn from(value: Vec<Bytes>) -> Self {
1058 Self(value.into_boxed_slice())
1059 }
1060}
1061
1062impl From<&[&[u8]]> for Keys {
1063 fn from(value: &[&[u8]]) -> Self {
1064 value.iter().copied().collect()
1065 }
1066}
1067
1068impl<B: Into<Bytes>> FromIterator<B> for Keys {
1069 fn from_iter<T: IntoIterator<Item = B>>(iter: T) -> Self {
1070 Self(iter.into_iter().map(Into::into).collect())
1071 }
1072}
1073
1074impl<'a> IntoIterator for &'a Keys {
1075 type Item = &'a Bytes;
1076 type IntoIter = core::slice::Iter<'a, Bytes>;
1077 fn into_iter(self) -> Self::IntoIter {
1078 self.0.iter()
1079 }
1080}
1081
1082impl ArchivedKeys {
1083 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
1084 self.0.iter().map(AsRef::as_ref)
1085 }
1086}
1087
1088pub type Bytes = Box<[u8]>;
1089
1090mod impls {
1091 use alloc::boxed::Box;
1092
1093 use super::{GraphId, PolicyId, StorageError, StorageProvider};
1094
1095 impl<SP: StorageProvider> StorageProvider for &mut SP {
1096 type Perspective = SP::Perspective;
1097 type Segment = SP::Segment;
1098 type Storage = SP::Storage;
1099
1100 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective {
1101 SP::new_perspective(self, policy_id)
1102 }
1103
1104 fn new_storage(
1105 &mut self,
1106 init: Self::Perspective,
1107 ) -> Result<(GraphId, &mut Self::Storage), StorageError> {
1108 SP::new_storage(self, init)
1109 }
1110
1111 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError> {
1112 SP::get_storage(self, graph)
1113 }
1114
1115 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError> {
1116 SP::remove_storage(self, graph)
1117 }
1118
1119 fn list_graph_ids(
1120 &mut self,
1121 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError> {
1122 SP::list_graph_ids(self)
1123 }
1124 }
1125
1126 impl<SP: StorageProvider> StorageProvider for Box<SP> {
1127 type Perspective = SP::Perspective;
1128 type Segment = SP::Segment;
1129 type Storage = SP::Storage;
1130
1131 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective {
1132 SP::new_perspective(self, policy_id)
1133 }
1134
1135 fn new_storage(
1136 &mut self,
1137 init: Self::Perspective,
1138 ) -> Result<(GraphId, &mut Self::Storage), StorageError> {
1139 SP::new_storage(self, init)
1140 }
1141
1142 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError> {
1143 SP::get_storage(self, graph)
1144 }
1145
1146 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError> {
1147 SP::remove_storage(self, graph)
1148 }
1149
1150 fn list_graph_ids(
1151 &mut self,
1152 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError> {
1153 SP::list_graph_ids(self)
1154 }
1155 }
1156}
1157
1158#[cfg(test)]
1159mod queue_tests {
1160 use super::*;
1161
1162 fn loc(seg: usize, mc: usize) -> Location {
1163 Location::new(SegmentIndex::new(seg as u64), MaxCut::new(mc as u64))
1164 }
1165
1166 #[test]
1167 fn test_queue_overflow_returns_error() {
1168 let mut queue = TraversalQueue::new();
1169 for i in 0..QUEUE_CAPACITY {
1171 queue.push(loc(i, i)).unwrap();
1172 }
1173 let result = queue
1175 .push(loc(999, 999))
1176 .expect_err("expected push_queue to fail");
1177 assert_eq!(result, StorageError::TraversalQueueOverflow(QUEUE_CAPACITY));
1178 }
1179
1180 #[test]
1181 fn test_push_defaults_covered_false() {
1182 let mut queue = TraversalQueue::new();
1183 queue.push(loc(0, 5)).unwrap();
1184 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1185 assert!(!covered);
1186 }
1187
1188 #[test]
1189 fn test_push_covered_preserves_flag() {
1190 let mut queue = TraversalQueue::new();
1191 queue.push_covered(loc(0, 5), true).unwrap();
1192 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1193 assert!(covered);
1194 }
1195
1196 #[test]
1197 fn test_push_covered_same_max_cut_ors_flags() {
1198 let mut queue = TraversalQueue::new();
1199 queue.push_covered(loc(0, 5), false).unwrap();
1200 queue.push_covered(loc(0, 5), true).unwrap();
1201 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1202 assert!(covered);
1203 }
1204
1205 #[test]
1206 fn test_push_covered_same_max_cut_cannot_uncover() {
1207 let mut queue = TraversalQueue::new();
1208 queue.push_covered(loc(0, 5), true).unwrap();
1209 queue.push_covered(loc(0, 5), false).unwrap();
1211 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1212 assert!(covered);
1213 }
1214
1215 #[test]
1216 fn test_push_same_segment_updates_max_cut() {
1217 let mut queue = TraversalQueue::new();
1218 queue.push(loc(0, 5)).unwrap();
1219 queue.push(loc(0, 8)).unwrap();
1220 let l = queue.pop().unwrap().unwrap();
1221 assert_eq!(l.max_cut, MaxCut::new(8));
1222 assert!(queue.is_empty());
1223 }
1224
1225 #[test]
1226 fn test_push_covered_higher_max_cut_adopts_new_flag() {
1227 let mut queue = TraversalQueue::new();
1228 queue.push_covered(loc(0, 5), true).unwrap();
1229 queue.push_covered(loc(0, 8), false).unwrap();
1231 let (l, covered) = queue.pop_covered().unwrap().unwrap();
1232 assert_eq!(l.max_cut, MaxCut::new(8));
1233 assert!(!covered);
1234 }
1235
1236 #[test]
1237 fn test_push_covered_lower_max_cut_no_change() {
1238 let mut queue = TraversalQueue::new();
1239 queue.push_covered(loc(0, 8), false).unwrap();
1240 queue.push_covered(loc(0, 3), true).unwrap();
1242 let (l, covered) = queue.pop_covered().unwrap().unwrap();
1243 assert_eq!(l.max_cut, MaxCut::new(8));
1244 assert!(!covered);
1245 }
1246
1247 #[test]
1248 fn test_pop_discards_covered_flag() {
1249 let mut queue = TraversalQueue::new();
1250 queue.push_covered(loc(0, 5), true).unwrap();
1251 let l = queue.pop().unwrap().unwrap();
1253 assert_eq!(l.max_cut, MaxCut::new(5));
1254 assert!(queue.is_empty());
1255 }
1256
1257 #[test]
1258 fn test_all_covered() {
1259 let mut queue = TraversalQueue::new();
1260 queue.push_covered(loc(0, 1), true).unwrap();
1261 queue.push_covered(loc(1, 2), true).unwrap();
1262 assert!(queue.all_covered());
1263
1264 queue.push_covered(loc(2, 3), false).unwrap();
1265 assert!(!queue.all_covered());
1266 }
1267
1268 #[test]
1269 fn test_drain_above() {
1270 let mut queue = TraversalQueue::new();
1271 queue.push(loc(0, 3)).unwrap();
1272 queue.push(loc(1, 7)).unwrap();
1273 queue.push(loc(2, 5)).unwrap();
1274
1275 let mut result: heapless::Vec<Location, 8> = heapless::Vec::new();
1276 queue
1277 .drain_above(MaxCut::new(4), |loc| {
1278 let _ = result.push(loc);
1279 })
1280 .unwrap();
1281
1282 assert_eq!(result.len(), 2);
1284 assert!(result.iter().any(|l| l.max_cut == MaxCut::new(7)));
1285 assert!(result.iter().any(|l| l.max_cut == MaxCut::new(5)));
1286
1287 let remaining = queue.pop().unwrap().unwrap();
1289 assert_eq!(remaining.max_cut, MaxCut::new(3));
1290 assert!(queue.is_empty());
1291 }
1292
1293 #[test]
1294 fn test_drain_above_with_covered_entries() {
1295 let mut queue = TraversalQueue::new();
1296 queue.push(loc(0, 3)).unwrap(); queue.push(loc(1, 7)).unwrap(); queue.push_covered(loc(2, 6), true).unwrap(); queue.push_covered(loc(3, 2), true).unwrap(); queue.push(loc(4, 5)).unwrap(); let mut drained: heapless::Vec<Location, 8> = heapless::Vec::new();
1304 queue
1305 .drain_above(MaxCut::new(4), |loc| {
1306 let _ = drained.push(loc);
1307 })
1308 .unwrap();
1309
1310 assert_eq!(drained.len(), 2);
1312 assert!(drained.iter().any(|l| l.segment.get() == 1));
1313 assert!(drained.iter().any(|l| l.segment.get() == 4));
1314
1315 let mut remaining = Vec::new();
1318 while let Some((l, covered)) = queue.pop_covered().unwrap() {
1319 remaining.push((l.segment, covered));
1320 }
1321 assert_eq!(remaining.len(), 2);
1322 assert!(remaining.contains(&(SegmentIndex::new(0), false)));
1323 assert!(remaining.contains(&(SegmentIndex::new(3), true)));
1324 }
1325
1326 #[test]
1327 fn test_push_duplicate_keeps_separate_entries() {
1328 let mut queue = TraversalQueue::new();
1329 queue.push_duplicate(loc(0, 5)).unwrap();
1330 queue.push_duplicate(loc(0, 5)).unwrap();
1331 let first = queue.pop().unwrap();
1332 assert!(first.is_some());
1333 let second = queue.pop().unwrap();
1334 assert!(second.is_some());
1335 assert!(queue.is_empty());
1336 }
1337
1338 #[test]
1339 fn test_push_duplicate_overflow() {
1340 let mut queue = TraversalQueue::new();
1341 for i in 0..QUEUE_CAPACITY {
1342 queue.push_duplicate(loc(0, i)).unwrap();
1343 }
1344 let result = queue.push_duplicate(loc(0, 999));
1345 assert_eq!(
1346 result.unwrap_err(),
1347 StorageError::TraversalQueueOverflow(QUEUE_CAPACITY)
1348 );
1349 }
1350
1351 #[test]
1352 fn test_pop_duplicates_returns_count() {
1353 let mut queue = TraversalQueue::new();
1354 queue.push_duplicate(loc(0, 5)).unwrap();
1355 queue.push_duplicate(loc(0, 5)).unwrap();
1356 queue.push_duplicate(loc(1, 3)).unwrap();
1357
1358 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1359 assert_eq!(location, loc(0, 5));
1360 assert_eq!(count, 2);
1361
1362 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1363 assert_eq!(location, loc(1, 3));
1364 assert_eq!(count, 1);
1365
1366 assert!(queue.pop_duplicates().unwrap().is_none());
1367 }
1368
1369 #[test]
1370 fn test_pop_duplicates_different_segments_same_max_cut() {
1371 let mut queue = TraversalQueue::new();
1372 queue.push_duplicate(loc(0, 5)).unwrap();
1373 queue.push_duplicate(loc(1, 5)).unwrap();
1374
1375 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1376 assert_eq!(count, 1);
1377 assert_eq!(location.max_cut, MaxCut::new(5));
1378
1379 let (_, count) = queue.pop_duplicates().unwrap().unwrap();
1380 assert_eq!(count, 1);
1381
1382 assert!(queue.pop_duplicates().unwrap().is_none());
1383 }
1384
1385 #[test]
1386 fn test_pop_duplicates_empty() {
1387 let mut queue = TraversalQueue::new();
1388 assert!(queue.pop_duplicates().unwrap().is_none());
1389 }
1390}