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, CommandExt as _, PolicyId, Prior};
15
16pub mod head_set;
17pub use head_set::HeadSet;
18
19pub mod linear;
20
21#[cfg(any(feature = "libc", feature = "testing"))]
22mod spill;
23#[cfg(feature = "libc")]
24pub use spill::LibcSpill;
25#[cfg(feature = "testing")]
26pub use spill::MemSpill;
27
28pub trait Spill {
35 fn write_at(&mut self, offset: usize, data: &[u8]) -> Result<(), StorageError>;
37 fn read_at(&mut self, offset: usize, data: &mut [u8]) -> Result<(), StorageError>;
39}
40
41pub const QUEUE_CAPACITY: usize = 512;
46
47#[derive(Debug, Default)]
57pub struct TraversalQueue {
58 entries: Vec<Location>,
59 partition: usize,
61}
62
63impl TraversalQueue {
64 pub const fn new() -> Self {
66 Self {
67 entries: Vec::new(),
68 partition: 0,
69 }
70 }
71
72 pub fn clear(&mut self) {
74 self.entries.clear();
75 self.partition = 0;
76 }
77
78 pub fn is_empty(&self) -> bool {
80 self.entries.is_empty()
81 }
82
83 pub fn push(&mut self, loc: Location) -> Result<(), StorageError> {
88 self.push_covered(loc, false)
89 }
90
91 pub fn push_covered(&mut self, loc: Location, covered: bool) -> Result<(), StorageError> {
98 if let Some(i) = self.entries.iter().position(|x| x.same_segment(loc)) {
99 let was_covered = i >= self.partition;
100 let new_covered = if loc.max_cut > self.entries[i].max_cut {
101 self.entries[i].max_cut = loc.max_cut;
102 covered
103 } else if loc.max_cut == self.entries[i].max_cut {
104 was_covered || covered
105 } else {
106 return Ok(());
107 };
108 if !was_covered && new_covered {
109 self.partition = self
110 .partition
111 .checked_sub(1)
112 .assume("partition must be >= 1 when uncovered entry exists")?;
113 self.entries.swap(i, self.partition);
114 } else if was_covered && !new_covered {
115 self.entries.swap(i, self.partition);
116 self.partition = self
117 .partition
118 .checked_add(1)
119 .assume("partition must not overflow")?;
120 }
121 return Ok(());
122 }
123 self.entries.push(loc);
124 if !covered {
125 let last = self
126 .entries
127 .len()
128 .checked_sub(1)
129 .assume("just pushed, len must be >= 1")?;
130 self.entries.swap(self.partition, last);
131 self.partition = self
132 .partition
133 .checked_add(1)
134 .assume("partition must not overflow")?;
135 }
136 Ok(())
137 }
138
139 pub fn push_duplicate(&mut self, loc: Location) -> Result<(), StorageError> {
145 self.entries.push(loc);
146 let last = self
148 .entries
149 .len()
150 .checked_sub(1)
151 .assume("just pushed, len must be >= 1")?;
152 self.entries.swap(self.partition, last);
153 self.partition = self
154 .partition
155 .checked_add(1)
156 .assume("partition must not overflow")?;
157 Ok(())
158 }
159
160 pub fn pop(&mut self) -> Result<Option<Location>, StorageError> {
162 Ok(self.pop_covered()?.map(|(loc, _)| loc))
163 }
164
165 pub fn pop_covered(&mut self) -> Result<Option<(Location, bool)>, StorageError> {
167 let Some((i, _)) = self.entries.iter().enumerate().max_by_key(|&(_, loc)| *loc) else {
168 return Ok(None);
169 };
170 if i < self.partition {
171 Ok(Some((self.remove_uncovered(i)?, false)))
172 } else {
173 let loc = self.entries.swap_remove(i);
175 Ok(Some((loc, true)))
176 }
177 }
178
179 fn remove_uncovered(&mut self, i: usize) -> Result<Location, StorageError> {
182 self.partition = self
183 .partition
184 .checked_sub(1)
185 .assume("partition must be >= 1 when uncovered entry exists")?;
186 self.entries.swap(i, self.partition);
187 Ok(self.entries.swap_remove(self.partition))
188 }
189
190 pub fn peek(&self) -> Option<&Location> {
192 self.entries.iter().max_by_key(|loc| *loc)
193 }
194
195 pub fn pop_duplicates(&mut self) -> Result<Option<(Location, usize)>, StorageError> {
201 let Some(location) = self.entries.iter().max_by_key(|loc| *loc).copied() else {
202 return Ok(None);
203 };
204
205 let mut count: usize = 0;
208 let mut j = self.entries.len();
209 while j > 0 {
210 j = j.checked_sub(1).assume("j > 0 checked in loop condition")?;
211 if self.entries[j] == location {
212 count = count
213 .checked_add(1)
214 .assume("count bounded by `entries.len()`")?;
215 if j < self.partition {
216 self.partition = self
217 .partition
218 .checked_sub(1)
219 .assume("partition >= 1 when uncovered entry at j < partition")?;
220 self.entries.swap(j, self.partition);
221 self.entries.swap_remove(self.partition);
222 } else {
223 self.entries.swap_remove(j);
224 }
225 }
226 }
227
228 Ok(Some((location, count)))
229 }
230
231 pub fn all_covered(&self) -> bool {
233 self.partition == 0
234 }
235
236 pub fn drain_above(
241 &mut self,
242 threshold: MaxCut,
243 mut f: impl FnMut(Location),
244 ) -> Result<(), StorageError> {
245 let mut i = 0;
247 while i < self.partition {
248 if self.entries[i].max_cut > threshold {
249 f(self.remove_uncovered(i)?);
250 } else {
251 i = i.checked_add(1).assume("index must not overflow")?;
252 }
253 }
254 let mut i = self.partition;
257 while i < self.entries.len() {
258 if self.entries[i].max_cut > threshold {
259 self.entries.swap_remove(i);
260 } else {
261 i = i.checked_add(1).assume("index must not overflow")?;
262 }
263 }
264 Ok(())
265 }
266
267 pub fn cover_up_to(
275 &mut self,
276 segment: SegmentIndex,
277 coverage_mc: MaxCut,
278 longest_mc: MaxCut,
279 ) -> Result<(), StorageError> {
280 let Some(i) = self.entries.iter().position(|x| x.segment == segment) else {
281 return Ok(());
282 };
283 let was_covered = i >= self.partition;
284 if was_covered {
285 return Ok(());
286 }
287 if coverage_mc >= longest_mc {
288 self.partition = self
290 .partition
291 .checked_sub(1)
292 .assume("partition must be >= 1 when uncovered entry exists")?;
293 self.entries.swap(i, self.partition);
294 } else if coverage_mc >= self.entries[i].max_cut {
295 self.entries[i].max_cut = coverage_mc
297 .checked_add(1)
298 .assume("coverage_mc + 1 must not overflow")?;
299 }
300 Ok(())
302 }
303
304 pub fn drain_all(&mut self, mut f: impl FnMut(Location)) {
307 for i in 0..self.partition {
308 f(self.entries[i]);
309 }
310 self.entries.clear();
311 self.partition = 0;
312 }
313}
314
315pub struct TraversalBuffer {
319 queue: TraversalQueue,
320}
321
322impl TraversalBuffer {
323 pub const fn new() -> Self {
324 Self {
325 queue: TraversalQueue::new(),
326 }
327 }
328
329 pub fn get(&mut self) -> &mut TraversalQueue {
331 self.queue.clear();
332 &mut self.queue
333 }
334}
335
336impl Default for TraversalBuffer {
337 fn default() -> Self {
338 Self::new()
339 }
340}
341
342pub struct TraversalBuffers {
348 pub primary: TraversalBuffer,
349 pub secondary: TraversalBuffer,
350}
351
352impl TraversalBuffers {
353 pub const fn new() -> Self {
354 Self {
355 primary: TraversalBuffer::new(),
356 secondary: TraversalBuffer::new(),
357 }
358 }
359}
360
361impl Default for TraversalBuffers {
362 fn default() -> Self {
363 Self::new()
364 }
365}
366
367#[cfg(feature = "low-mem-usage")]
368pub const MAX_COMMAND_LENGTH: usize = 400;
369#[cfg(not(feature = "low-mem-usage"))]
370pub const MAX_COMMAND_LENGTH: usize = 2048;
371
372aranya_crypto::custom_id! {
373 pub struct GraphId;
375}
376
377#[derive(
378 Copy,
379 Clone,
380 Debug,
381 Hash,
382 PartialEq,
383 Eq,
384 PartialOrd,
385 Ord,
386 serde::Serialize,
387 serde::Deserialize,
388 rkyv::Archive,
389 rkyv::Serialize,
390 rkyv::Deserialize,
391 rkyv::Portable,
392 rkyv::bytecheck::CheckBytes,
393 zerocopy::IntoBytes,
394 zerocopy::FromBytes,
395 zerocopy::Immutable,
396 zerocopy::KnownLayout,
397)]
398#[rkyv(as = Self)]
399#[bytecheck(crate = rkyv::bytecheck)]
400#[serde(transparent)]
401#[repr(transparent)]
402pub struct SegmentIndex(#[serde(with = "crate::util::u64_le_serde")] u64_le);
403
404impl fmt::Display for SegmentIndex {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 fmt::Display::fmt(&self.0, f)
407 }
408}
409
410impl SegmentIndex {
411 pub const fn new(val: u64) -> Self {
412 Self(u64_le::from_native(val))
413 }
414
415 pub const fn get(self) -> u64 {
416 self.0.to_native()
417 }
418}
419
420#[derive(
421 Copy,
422 Clone,
423 Debug,
424 Hash,
425 PartialEq,
426 Eq,
427 PartialOrd,
428 Ord,
429 serde::Serialize,
430 serde::Deserialize,
431 rkyv::Archive,
432 rkyv::Serialize,
433 rkyv::Deserialize,
434 rkyv::Portable,
435 rkyv::bytecheck::CheckBytes,
436 zerocopy::IntoBytes,
437 zerocopy::FromBytes,
438 zerocopy::Immutable,
439 zerocopy::KnownLayout,
440)]
441#[rkyv(as = Self)]
442#[bytecheck(crate = rkyv::bytecheck)]
443#[serde(transparent)]
444#[repr(transparent)]
445pub struct MaxCut(#[serde(with = "crate::util::u64_le_serde")] u64_le);
446
447impl fmt::Display for MaxCut {
448 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449 fmt::Display::fmt(&self.0, f)
450 }
451}
452
453impl MaxCut {
454 pub const fn new(val: u64) -> Self {
455 Self(u64_le::from_native(val))
456 }
457
458 pub const fn get(self) -> u64 {
459 self.0.to_native()
460 }
461
462 #[must_use]
464 pub fn checked_add(self, other: u64) -> Option<Self> {
465 self.get().checked_add(other).map(Self::new)
466 }
467
468 #[must_use]
470 pub fn decremented(self) -> Option<Self> {
471 self.get().checked_sub(1).map(Self::new)
472 }
473
474 #[must_use]
476 pub fn distance_from(self, other: Self) -> Option<u64> {
477 self.get().checked_sub(other.get())
478 }
479}
480
481#[derive(
482 Copy,
483 Clone,
484 Debug,
485 Hash,
486 PartialEq,
487 Eq,
488 PartialOrd,
489 Ord,
490 serde::Serialize,
491 serde::Deserialize,
492 rkyv::Archive,
493 rkyv::Serialize,
494 rkyv::Deserialize,
495 rkyv::Portable,
496 rkyv::bytecheck::CheckBytes,
497 zerocopy::IntoBytes,
498 zerocopy::FromBytes,
499 zerocopy::Immutable,
500 zerocopy::KnownLayout,
501)]
502#[rkyv(as = Self)]
503#[bytecheck(crate = rkyv::bytecheck)]
504#[repr(C)]
505pub struct Location {
506 pub max_cut: MaxCut,
507 pub segment: SegmentIndex,
508}
509
510impl From<(SegmentIndex, MaxCut)> for Location {
511 fn from((segment, max_cut): (SegmentIndex, MaxCut)) -> Self {
512 Self::new(segment, max_cut)
513 }
514}
515
516impl AsRef<Self> for Location {
517 fn as_ref(&self) -> &Self {
518 self
519 }
520}
521
522impl Location {
523 pub fn new(segment: SegmentIndex, max_cut: MaxCut) -> Self {
524 Self { max_cut, segment }
525 }
526
527 pub fn same_segment(self, other: Self) -> bool {
529 self.segment == other.segment
530 }
531}
532
533impl fmt::Display for Location {
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 write!(f, "{}:{}", self.segment, self.max_cut)
536 }
537}
538
539#[derive(
540 Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
541)]
542pub struct LocatedAddress {
543 pub id: CmdId,
544 pub segment: SegmentIndex,
545 pub max_cut: MaxCut,
546}
547
548impl LocatedAddress {
549 pub fn address(self) -> Address {
550 Address {
551 id: self.id,
552 max_cut: self.max_cut,
553 }
554 }
555
556 pub fn location(self) -> Location {
557 Location {
558 segment: self.segment,
559 max_cut: self.max_cut,
560 }
561 }
562}
563
564#[derive(Clone, Copy, Debug, PartialEq, Eq)]
569pub struct HeadSetOffset(u64);
570
571impl HeadSetOffset {
572 pub fn new(offset: u64) -> Self {
574 Self(offset)
575 }
576}
577
578#[derive(Debug, thiserror::Error)]
580#[cfg_attr(test, derive(PartialEq, Eq))]
581#[non_exhaustive]
582pub enum StorageError {
583 #[error("storage already exists")]
584 StorageExists,
585 #[error("no such storage")]
586 NoSuchStorage,
587 #[error("storage created but not initialized by a first commit")]
588 NotInitialized,
589 #[error("segment index {} is out of bounds", .0.segment)]
590 SegmentOutOfBounds(Location),
591 #[error("max cut {} is out of bounds in segment {}", .0.max_cut, .0.segment)]
592 CommandOutOfBounds(Location),
593 #[error("IO error")]
594 IoError,
595 #[error("policy mismatch")]
596 PolicyMismatch,
597 #[error("cannot write an empty perspective")]
598 EmptyPerspective,
599 #[error("traversal queue overflow (capacity {0})")]
600 TraversalQueueOverflow(usize),
601 #[error("strand heap overflow (capacity {0})")]
602 StrandHeapOverflow(usize),
603 #[error("convergence root index overflow (capacity {0})")]
604 ConvergenceRootOverflow(usize),
605 #[error("command's parents do not match the perspective head")]
606 PerspectiveHeadMismatch,
607 #[error("graph has multiple heads ({0}); no single head to report")]
608 MultipleHeads(usize),
609 #[error(transparent)]
610 Bug(#[from] Bug),
611}
612
613pub trait StorageProvider {
615 type Perspective: Perspective + Revertable;
616 type Segment: Segment;
617 type Storage: Storage<
618 Segment = Self::Segment,
619 Perspective = Self::Perspective,
620 FactIndex = <Self::Segment as Segment>::FactIndex,
621 >;
622
623 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective;
629
630 fn new_storage(
637 &mut self,
638 init: Self::Perspective,
639 ) -> Result<(GraphId, &mut Self::Storage), StorageError>;
640
641 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError>;
647
648 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError>;
654
655 fn list_graph_ids(
658 &mut self,
659 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError>;
660}
661
662fn search_queued<S: Storage + ?Sized>(
668 storage: &S,
669 address: Address,
670 queue: &mut TraversalQueue,
671) -> Result<Option<Location>, StorageError> {
672 while let Some(loc) = queue.pop()? {
673 debug_assert!(
674 loc.max_cut >= address.max_cut,
675 "Invariant: we only enqueue locations with at least the target max cut"
676 );
677
678 let segment = storage.get_segment(loc)?;
680
681 if let Some(found) = segment.get_by_address(address) {
683 return Ok(Some(found));
684 }
685
686 if let Some(&skip) = segment
691 .skip_list()
692 .iter()
693 .find(|skip| skip.max_cut >= address.max_cut)
694 {
695 queue.push(skip)?;
696 } else {
697 for prior in segment.prior() {
699 if prior.max_cut >= address.max_cut {
700 queue.push(prior)?;
701 }
702 }
703 }
704 }
705 Ok(None)
706}
707
708pub trait Storage {
711 type Perspective: Perspective + Revertable;
712 type FactPerspective: FactPerspective;
713 type Segment: Segment<FactIndex = Self::FactIndex>;
714 type FactIndex: FactIndex;
715
716 fn get_location(
719 &self,
720 address: Address,
721 buffer: &mut TraversalBuffer,
722 ) -> Result<Option<Location>, StorageError> {
723 let queue = buffer.get();
727 for head in self.get_heads()?.iter() {
728 if head.max_cut >= address.max_cut {
729 queue.push(head.location())?;
730 }
731 }
732 search_queued(self, address, queue)
733 }
734
735 fn get_location_from(
739 &self,
740 start: Location,
741 address: Address,
742 buffer: &mut TraversalBuffer,
743 ) -> Result<Option<Location>, StorageError> {
744 if start.max_cut < address.max_cut {
745 return Ok(None);
746 }
747
748 let queue = buffer.get();
749 queue.push(start)?;
750 search_queued(self, address, queue)
751 }
752
753 fn get_command_address(&self, location: Location) -> Result<Address, StorageError> {
757 let segment = self.get_segment(location)?;
758 let command = segment
759 .get_command(location)
760 .ok_or(StorageError::CommandOutOfBounds(location))?;
761 let address = command.address()?;
762 Ok(address)
763 }
764
765 fn get_linear_perspective(&self, parent: Location) -> Result<Self::Perspective, StorageError>;
767
768 fn get_fact_perspective(&self, first: Location) -> Result<Self::FactPerspective, StorageError>;
771
772 fn new_merge_perspective(
774 &self,
775 left: Location,
776 right: Location,
777 last_common_ancestor: Location,
778 policy_id: PolicyId,
779 braid: Self::FactIndex,
780 ) -> Result<Self::Perspective, StorageError>;
781
782 fn get_segment(&self, location: Location) -> Result<Self::Segment, StorageError>;
784
785 fn get_heads(&self) -> Result<&HeadSet, StorageError>;
791
792 fn heads_offset(&self) -> Result<HeadSetOffset, StorageError>;
797
798 fn fact_cache(&self) -> Result<Self::FactIndex, StorageError>;
800
801 fn commit_heads(
803 &mut self,
804 heads: HeadSet,
805 fact_cache: Self::FactIndex,
806 ) -> Result<(), StorageError>;
807
808 fn get_head_address(&self) -> Result<Address, StorageError> {
819 let heads = self.get_heads()?;
820 let mut it = heads.iter();
821 let first = it.next().assume("initialized graph always has >= 1 head")?;
822 if it.next().is_some() {
823 return Err(StorageError::MultipleHeads(heads.len()));
824 }
825 Ok(first.address())
826 }
827
828 fn write(&mut self, perspective: Self::Perspective) -> Result<Self::Segment, StorageError>;
830
831 fn write_facts(
833 &mut self,
834 fact_perspective: Self::FactPerspective,
835 ) -> Result<Self::FactIndex, StorageError>;
836
837 fn is_ancestor(
839 &self,
840 search_location: Location,
841 start_location: Location,
842 buffer: &mut TraversalBuffer,
843 ) -> Result<bool, StorageError> {
844 if search_location.max_cut > start_location.max_cut || search_location == start_location {
845 return Ok(false);
846 }
847
848 let queue = buffer.get();
849 queue.push(start_location)?;
850
851 while let Some(loc) = queue.pop()? {
852 debug_assert!(
853 loc.max_cut >= search_location.max_cut,
854 "Invariant: we only enqueue locations with at least the target max cut"
855 );
856
857 let segment = self.get_segment(loc)?;
859
860 if segment.get_command(search_location).is_some() {
862 return Ok(true);
863 }
864
865 if let Some(&skip) = segment
870 .skip_list()
871 .iter()
872 .find(|skip| skip.max_cut >= search_location.max_cut)
873 {
874 queue.push(skip)?;
875 } else {
876 for prior in segment.prior() {
878 if prior.max_cut >= search_location.max_cut {
879 queue.push(prior)?;
880 }
881 }
882 }
883 }
884 Ok(false)
885 }
886}
887
888pub trait Segment {
898 type FactIndex: FactIndex;
899 type Command<'a>: Command
900 where
901 Self: 'a;
902
903 fn index(&self) -> SegmentIndex;
905
906 fn head_id(&self) -> CmdId;
908
909 fn policy(&self) -> PolicyId;
911
912 fn prior(&self) -> Prior<Location>;
914
915 fn get_command(&self, location: Location) -> Option<Self::Command<'_>>;
917
918 fn facts(&self) -> Result<Self::FactIndex, StorageError>;
920
921 fn shortest_max_cut(&self) -> MaxCut;
925
926 fn longest_max_cut(&self) -> Result<MaxCut, StorageError>;
930
931 fn skip_list(&self) -> &[Location];
940
941 fn get_from(&self, location: Location) -> Vec<Self::Command<'_>> {
943 let segment = location.segment;
944 core::iter::successors(Some(location.max_cut), |max_cut| max_cut.checked_add(1))
945 .map_while(|max_cut| self.get_command(Location { max_cut, segment }))
946 .collect()
947 }
948
949 fn get_by_address(&self, address: Address) -> Option<Location> {
951 let loc = Location::new(self.index(), address.max_cut);
952 let cmd = self.get_command(loc)?;
953 if cmd.id() != address.id {
954 return None;
955 }
956 Some(loc)
957 }
958
959 fn first_location(&self) -> Location {
961 Location {
962 max_cut: self.shortest_max_cut(),
963 segment: self.index(),
964 }
965 }
966
967 fn head_location(&self) -> Result<Location, StorageError> {
969 Ok(Location {
970 max_cut: self.longest_max_cut()?,
971 segment: self.index(),
972 })
973 }
974
975 fn head_address(&self) -> Result<Address, StorageError> {
977 Ok(Address {
978 id: self.head_id(),
979 max_cut: self.longest_max_cut()?,
980 })
981 }
982
983 #[must_use]
985 fn previous(&self, mut location: Location) -> Option<Location> {
986 debug_assert_eq!(location.segment, self.index());
987 if location.max_cut <= self.shortest_max_cut() {
988 return None;
989 }
990 location.max_cut = location.max_cut.decremented()?;
991 Some(location)
992 }
993}
994
995pub trait FactIndex: Query {}
997
998pub trait Perspective: FactPerspective {
1001 fn policy(&self) -> PolicyId;
1003
1004 fn add_command(&mut self, command: &impl Command) -> Result<usize, StorageError>;
1007
1008 fn includes(&self, id: CmdId) -> bool;
1010
1011 fn head_address(&self) -> Result<Prior<Address>, Bug>;
1013}
1014
1015pub trait FactPerspective: QueryMut {}
1017
1018pub trait Revertable {
1021 fn checkpoint(&self) -> Checkpoint;
1023
1024 fn revert(&mut self, checkpoint: Checkpoint) -> Result<(), StorageError>;
1026}
1027
1028pub struct Checkpoint {
1030 pub index: usize,
1032}
1033
1034pub trait Query {
1041 fn query(&self, name: &str, keys: &[Bytes]) -> Result<Option<Bytes>, StorageError>;
1043
1044 type QueryIterator: Iterator<Item = Result<Fact, StorageError>>;
1046
1047 fn query_prefix(
1052 &self,
1053 name: &str,
1054 prefix: &[Bytes],
1055 ) -> Result<Self::QueryIterator, StorageError>;
1056}
1057
1058#[derive(Debug, PartialEq, Eq)]
1060pub struct Fact {
1061 pub key: Keys,
1063 pub value: Bytes,
1065}
1066
1067pub trait QueryMut: Query {
1071 fn insert(&mut self, name: String, keys: Keys, value: Bytes) -> Result<(), StorageError>;
1075
1076 fn delete(&mut self, name: String, keys: Keys) -> Result<(), StorageError>;
1078}
1079
1080#[cfg(all(test, feature = "graphviz"))]
1082pub(crate) trait FactIndexExtra {
1083 fn name(&self) -> String;
1084 fn prior(&self) -> Result<Option<Self>, StorageError>
1085 where
1086 Self: Sized;
1087}
1088
1089#[derive(
1091 Clone,
1092 Debug,
1093 Default,
1094 PartialEq,
1095 Eq,
1096 PartialOrd,
1097 Ord,
1098 serde::Serialize,
1099 serde::Deserialize,
1100 rkyv::Archive,
1101 rkyv::Serialize,
1102 rkyv::Deserialize,
1103)]
1104pub struct Keys(Box<[Bytes]>);
1105
1106impl Deref for Keys {
1107 type Target = [Bytes];
1108 fn deref(&self) -> &[Bytes] {
1109 self.0.as_ref()
1110 }
1111}
1112
1113impl AsRef<[Bytes]> for Keys {
1114 fn as_ref(&self) -> &[Bytes] {
1115 self.0.as_ref()
1116 }
1117}
1118
1119impl Borrow<[Bytes]> for Keys {
1120 fn borrow(&self) -> &[Bytes] {
1121 self.0.as_ref()
1122 }
1123}
1124
1125impl From<Vec<Bytes>> for Keys {
1126 fn from(value: Vec<Bytes>) -> Self {
1127 Self(value.into_boxed_slice())
1128 }
1129}
1130
1131impl From<&[&[u8]]> for Keys {
1132 fn from(value: &[&[u8]]) -> Self {
1133 value.iter().copied().collect()
1134 }
1135}
1136
1137impl<B: Into<Bytes>> FromIterator<B> for Keys {
1138 fn from_iter<T: IntoIterator<Item = B>>(iter: T) -> Self {
1139 Self(iter.into_iter().map(Into::into).collect())
1140 }
1141}
1142
1143impl<'a> IntoIterator for &'a Keys {
1144 type Item = &'a Bytes;
1145 type IntoIter = core::slice::Iter<'a, Bytes>;
1146 fn into_iter(self) -> Self::IntoIter {
1147 self.0.iter()
1148 }
1149}
1150
1151impl ArchivedKeys {
1152 pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
1153 self.0.iter().map(AsRef::as_ref)
1154 }
1155}
1156
1157pub type Bytes = Box<[u8]>;
1158
1159mod impls {
1160 use alloc::boxed::Box;
1161
1162 use super::{GraphId, PolicyId, StorageError, StorageProvider};
1163
1164 impl<SP: StorageProvider> StorageProvider for &mut SP {
1165 type Perspective = SP::Perspective;
1166 type Segment = SP::Segment;
1167 type Storage = SP::Storage;
1168
1169 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective {
1170 SP::new_perspective(self, policy_id)
1171 }
1172
1173 fn new_storage(
1174 &mut self,
1175 init: Self::Perspective,
1176 ) -> Result<(GraphId, &mut Self::Storage), StorageError> {
1177 SP::new_storage(self, init)
1178 }
1179
1180 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError> {
1181 SP::get_storage(self, graph)
1182 }
1183
1184 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError> {
1185 SP::remove_storage(self, graph)
1186 }
1187
1188 fn list_graph_ids(
1189 &mut self,
1190 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError> {
1191 SP::list_graph_ids(self)
1192 }
1193 }
1194
1195 impl<SP: StorageProvider> StorageProvider for Box<SP> {
1196 type Perspective = SP::Perspective;
1197 type Segment = SP::Segment;
1198 type Storage = SP::Storage;
1199
1200 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective {
1201 SP::new_perspective(self, policy_id)
1202 }
1203
1204 fn new_storage(
1205 &mut self,
1206 init: Self::Perspective,
1207 ) -> Result<(GraphId, &mut Self::Storage), StorageError> {
1208 SP::new_storage(self, init)
1209 }
1210
1211 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError> {
1212 SP::get_storage(self, graph)
1213 }
1214
1215 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError> {
1216 SP::remove_storage(self, graph)
1217 }
1218
1219 fn list_graph_ids(
1220 &mut self,
1221 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError> {
1222 SP::list_graph_ids(self)
1223 }
1224 }
1225}
1226
1227#[cfg(test)]
1228mod queue_tests {
1229 use super::*;
1230
1231 fn loc(seg: usize, mc: usize) -> Location {
1232 Location::new(SegmentIndex::new(seg as u64), MaxCut::new(mc as u64))
1233 }
1234
1235 #[test]
1236 #[ignore = "queue is currently unbounded"]
1237 fn test_queue_overflow_returns_error() {
1238 let mut queue = TraversalQueue::new();
1239 for i in 0..QUEUE_CAPACITY {
1241 queue.push(loc(i, i)).unwrap();
1242 }
1243 let result = queue
1245 .push(loc(999, 999))
1246 .expect_err("expected push_queue to fail");
1247 assert_eq!(result, StorageError::TraversalQueueOverflow(QUEUE_CAPACITY));
1248 }
1249
1250 #[test]
1251 fn test_push_defaults_covered_false() {
1252 let mut queue = TraversalQueue::new();
1253 queue.push(loc(0, 5)).unwrap();
1254 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1255 assert!(!covered);
1256 }
1257
1258 #[test]
1259 fn test_push_covered_preserves_flag() {
1260 let mut queue = TraversalQueue::new();
1261 queue.push_covered(loc(0, 5), true).unwrap();
1262 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1263 assert!(covered);
1264 }
1265
1266 #[test]
1267 fn test_push_covered_same_max_cut_ors_flags() {
1268 let mut queue = TraversalQueue::new();
1269 queue.push_covered(loc(0, 5), false).unwrap();
1270 queue.push_covered(loc(0, 5), true).unwrap();
1271 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1272 assert!(covered);
1273 }
1274
1275 #[test]
1276 fn test_push_covered_same_max_cut_cannot_uncover() {
1277 let mut queue = TraversalQueue::new();
1278 queue.push_covered(loc(0, 5), true).unwrap();
1279 queue.push_covered(loc(0, 5), false).unwrap();
1281 let (_, covered) = queue.pop_covered().unwrap().unwrap();
1282 assert!(covered);
1283 }
1284
1285 #[test]
1286 fn test_push_same_segment_updates_max_cut() {
1287 let mut queue = TraversalQueue::new();
1288 queue.push(loc(0, 5)).unwrap();
1289 queue.push(loc(0, 8)).unwrap();
1290 let l = queue.pop().unwrap().unwrap();
1291 assert_eq!(l.max_cut, MaxCut::new(8));
1292 assert!(queue.is_empty());
1293 }
1294
1295 #[test]
1296 fn test_push_covered_higher_max_cut_adopts_new_flag() {
1297 let mut queue = TraversalQueue::new();
1298 queue.push_covered(loc(0, 5), true).unwrap();
1299 queue.push_covered(loc(0, 8), false).unwrap();
1301 let (l, covered) = queue.pop_covered().unwrap().unwrap();
1302 assert_eq!(l.max_cut, MaxCut::new(8));
1303 assert!(!covered);
1304 }
1305
1306 #[test]
1307 fn test_push_covered_lower_max_cut_no_change() {
1308 let mut queue = TraversalQueue::new();
1309 queue.push_covered(loc(0, 8), false).unwrap();
1310 queue.push_covered(loc(0, 3), true).unwrap();
1312 let (l, covered) = queue.pop_covered().unwrap().unwrap();
1313 assert_eq!(l.max_cut, MaxCut::new(8));
1314 assert!(!covered);
1315 }
1316
1317 #[test]
1318 fn test_pop_discards_covered_flag() {
1319 let mut queue = TraversalQueue::new();
1320 queue.push_covered(loc(0, 5), true).unwrap();
1321 let l = queue.pop().unwrap().unwrap();
1323 assert_eq!(l.max_cut, MaxCut::new(5));
1324 assert!(queue.is_empty());
1325 }
1326
1327 #[test]
1328 fn test_all_covered() {
1329 let mut queue = TraversalQueue::new();
1330 queue.push_covered(loc(0, 1), true).unwrap();
1331 queue.push_covered(loc(1, 2), true).unwrap();
1332 assert!(queue.all_covered());
1333
1334 queue.push_covered(loc(2, 3), false).unwrap();
1335 assert!(!queue.all_covered());
1336 }
1337
1338 #[test]
1339 fn test_drain_above() {
1340 let mut queue = TraversalQueue::new();
1341 queue.push(loc(0, 3)).unwrap();
1342 queue.push(loc(1, 7)).unwrap();
1343 queue.push(loc(2, 5)).unwrap();
1344
1345 let mut result: heapless::Vec<Location, 8> = heapless::Vec::new();
1346 queue
1347 .drain_above(MaxCut::new(4), |loc| {
1348 let _ = result.push(loc);
1349 })
1350 .unwrap();
1351
1352 assert_eq!(result.len(), 2);
1354 assert!(result.iter().any(|l| l.max_cut == MaxCut::new(7)));
1355 assert!(result.iter().any(|l| l.max_cut == MaxCut::new(5)));
1356
1357 let remaining = queue.pop().unwrap().unwrap();
1359 assert_eq!(remaining.max_cut, MaxCut::new(3));
1360 assert!(queue.is_empty());
1361 }
1362
1363 #[test]
1364 fn test_drain_above_with_covered_entries() {
1365 let mut queue = TraversalQueue::new();
1366 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();
1374 queue
1375 .drain_above(MaxCut::new(4), |loc| {
1376 let _ = drained.push(loc);
1377 })
1378 .unwrap();
1379
1380 assert_eq!(drained.len(), 2);
1382 assert!(drained.iter().any(|l| l.segment.get() == 1));
1383 assert!(drained.iter().any(|l| l.segment.get() == 4));
1384
1385 let mut remaining = Vec::new();
1388 while let Some((l, covered)) = queue.pop_covered().unwrap() {
1389 remaining.push((l.segment, covered));
1390 }
1391 assert_eq!(remaining.len(), 2);
1392 assert!(remaining.contains(&(SegmentIndex::new(0), false)));
1393 assert!(remaining.contains(&(SegmentIndex::new(3), true)));
1394 }
1395
1396 #[test]
1397 fn test_push_duplicate_keeps_separate_entries() {
1398 let mut queue = TraversalQueue::new();
1399 queue.push_duplicate(loc(0, 5)).unwrap();
1400 queue.push_duplicate(loc(0, 5)).unwrap();
1401 let first = queue.pop().unwrap();
1402 assert!(first.is_some());
1403 let second = queue.pop().unwrap();
1404 assert!(second.is_some());
1405 assert!(queue.is_empty());
1406 }
1407
1408 #[test]
1409 #[ignore = "queue is currently unbounded"]
1410 fn test_push_duplicate_overflow() {
1411 let mut queue = TraversalQueue::new();
1412 for i in 0..QUEUE_CAPACITY {
1413 queue.push_duplicate(loc(0, i)).unwrap();
1414 }
1415 let result = queue.push_duplicate(loc(0, 999));
1416 assert_eq!(
1417 result.unwrap_err(),
1418 StorageError::TraversalQueueOverflow(QUEUE_CAPACITY)
1419 );
1420 }
1421
1422 #[test]
1423 fn test_pop_duplicates_returns_count() {
1424 let mut queue = TraversalQueue::new();
1425 queue.push_duplicate(loc(0, 5)).unwrap();
1426 queue.push_duplicate(loc(0, 5)).unwrap();
1427 queue.push_duplicate(loc(1, 3)).unwrap();
1428
1429 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1430 assert_eq!(location, loc(0, 5));
1431 assert_eq!(count, 2);
1432
1433 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1434 assert_eq!(location, loc(1, 3));
1435 assert_eq!(count, 1);
1436
1437 assert!(queue.pop_duplicates().unwrap().is_none());
1438 }
1439
1440 #[test]
1441 fn test_pop_duplicates_different_segments_same_max_cut() {
1442 let mut queue = TraversalQueue::new();
1443 queue.push_duplicate(loc(0, 5)).unwrap();
1444 queue.push_duplicate(loc(1, 5)).unwrap();
1445
1446 let (location, count) = queue.pop_duplicates().unwrap().unwrap();
1447 assert_eq!(count, 1);
1448 assert_eq!(location.max_cut, MaxCut::new(5));
1449
1450 let (_, count) = queue.pop_duplicates().unwrap().unwrap();
1451 assert_eq!(count, 1);
1452
1453 assert!(queue.pop_duplicates().unwrap().is_none());
1454 }
1455
1456 #[test]
1457 fn test_pop_duplicates_empty() {
1458 let mut queue = TraversalQueue::new();
1459 assert!(queue.pop_duplicates().unwrap().is_none());
1460 }
1461}