1use alloc::{boxed::Box, string::String, vec::Vec};
9use core::{fmt, ops::Deref};
10
11use buggy::{Bug, BugExt as _};
12use serde::{Deserialize, Serialize};
13
14use crate::{Address, CmdId, Command, PolicyId, Prior};
15
16pub mod linear;
17pub mod memory;
18
19pub const MAX_COMMAND_LENGTH: usize = 2048;
21
22aranya_crypto::custom_id! {
23 pub struct GraphId;
25}
26
27#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
28pub struct Location {
29 pub segment: usize,
30 pub command: usize,
31}
32
33impl From<(usize, usize)> for Location {
34 fn from((segment, command): (usize, usize)) -> Self {
35 Self::new(segment, command)
36 }
37}
38
39impl AsRef<Self> for Location {
40 fn as_ref(&self) -> &Self {
41 self
42 }
43}
44
45impl Location {
46 pub fn new(segment: usize, command: usize) -> Self {
47 Self { segment, command }
48 }
49
50 #[must_use]
53 pub fn previous(mut self) -> Option<Self> {
54 if let Some(n) = usize::checked_sub(self.command, 1) {
55 self.command = n;
56 Some(self)
57 } else {
58 None
59 }
60 }
61
62 pub fn same_segment(self, other: Self) -> bool {
64 self.segment == other.segment
65 }
66}
67
68impl fmt::Display for Location {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{}:{}", self.segment, self.command)
71 }
72}
73
74#[derive(Debug, PartialEq, Eq, thiserror::Error)]
76pub enum StorageError {
77 #[error("storage already exists")]
78 StorageExists,
79 #[error("no such storage")]
80 NoSuchStorage,
81 #[error("segment index {} is out of bounds", .0.segment)]
82 SegmentOutOfBounds(Location),
83 #[error("command index {} is out of bounds in segment {}", .0.command, .0.segment)]
84 CommandOutOfBounds(Location),
85 #[error("IO error")]
86 IoError,
87 #[error("not a merge command")]
88 NotMerge,
89 #[error("command with id {0} not found")]
90 NoSuchId(CmdId),
91 #[error("policy mismatch")]
92 PolicyMismatch,
93 #[error("cannot write an empty perspective")]
94 EmptyPerspective,
95 #[error("segment must be a descendant of the head for commit")]
96 HeadNotAncestor,
97 #[error("command's parents do not match the perspective head")]
98 PerspectiveHeadMismatch,
99 #[error(transparent)]
100 Bug(#[from] Bug),
101}
102
103pub trait StorageProvider {
105 type Perspective: Perspective + Revertable;
106 type Segment: Segment;
107 type Storage: Storage<
108 Segment = Self::Segment,
109 Perspective = Self::Perspective,
110 FactIndex = <Self::Segment as Segment>::FactIndex,
111 >;
112
113 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective;
119
120 fn new_storage(
127 &mut self,
128 init: Self::Perspective,
129 ) -> Result<(GraphId, &mut Self::Storage), StorageError>;
130
131 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError>;
137
138 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError>;
144
145 fn list_graph_ids(
148 &mut self,
149 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError>;
150}
151
152pub trait Storage {
155 type Perspective: Perspective + Revertable;
156 type FactPerspective: FactPerspective;
157 type Segment: Segment<FactIndex = Self::FactIndex>;
158 type FactIndex: FactIndex;
159
160 fn get_location(&self, address: Address) -> Result<Option<Location>, StorageError> {
163 self.get_location_from(self.get_head()?, address)
164 }
165
166 fn get_location_from(
168 &self,
169 start: Location,
170 address: Address,
171 ) -> Result<Option<Location>, StorageError> {
172 let mut queue = Vec::new();
173 queue.push(start);
174 'outer: while let Some(loc) = queue.pop() {
175 let head = self.get_segment(loc)?;
176 if address.max_cut > head.longest_max_cut()? {
177 continue;
178 }
179 if let Some(loc) = head.get_by_address(address) {
180 return Ok(Some(loc));
181 }
182 for (skip, max_cut) in head.skip_list() {
185 if max_cut >= &address.max_cut {
186 queue.push(*skip);
187 continue 'outer;
188 }
189 }
190 queue.extend(head.prior());
191 }
192 Ok(None)
193 }
194
195 fn get_command_address(&self, location: Location) -> Result<Address, StorageError> {
199 let segment = self.get_segment(location)?;
200 let command = segment
201 .get_command(location)
202 .ok_or(StorageError::CommandOutOfBounds(location))?;
203 let address = command.address()?;
204 Ok(address)
205 }
206
207 fn get_linear_perspective(&self, parent: Location) -> Result<Self::Perspective, StorageError>;
209
210 fn get_fact_perspective(&self, first: Location) -> Result<Self::FactPerspective, StorageError>;
213
214 fn new_merge_perspective(
216 &self,
217 left: Location,
218 right: Location,
219 last_common_ancestor: (Location, usize),
220 policy_id: PolicyId,
221 braid: Self::FactIndex,
222 ) -> Result<Self::Perspective, StorageError>;
223
224 fn get_segment(&self, location: Location) -> Result<Self::Segment, StorageError>;
226
227 fn get_head(&self) -> Result<Location, StorageError>;
229
230 fn get_head_address(&self) -> Result<Address, StorageError> {
232 self.get_command_address(self.get_head()?)
233 }
234
235 fn commit(&mut self, segment: Self::Segment) -> Result<(), StorageError>;
238
239 fn write(&mut self, perspective: Self::Perspective) -> Result<Self::Segment, StorageError>;
241
242 fn write_facts(
244 &mut self,
245 fact_perspective: Self::FactPerspective,
246 ) -> Result<Self::FactIndex, StorageError>;
247
248 fn is_ancestor(
250 &self,
251 search_location: Location,
252 segment: &Self::Segment,
253 ) -> Result<bool, StorageError> {
254 let mut queue = Vec::new();
255 queue.extend(segment.prior());
256 let segment = self.get_segment(search_location)?;
257 let address = segment
258 .get_command(search_location)
259 .assume("location must exist")?
260 .address()?;
261 'outer: while let Some(location) = queue.pop() {
262 if location.segment == search_location.segment
263 && location.command >= search_location.command
264 {
265 return Ok(true);
266 }
267 let segment = self.get_segment(location)?;
268 if address.max_cut > segment.longest_max_cut()? {
269 continue;
270 }
271 for (skip, max_cut) in segment.skip_list() {
272 if max_cut >= &address.max_cut {
273 queue.push(*skip);
274 continue 'outer;
275 }
276 }
277 queue.extend(segment.prior());
278 }
279 Ok(false)
280 }
281}
282
283type MaxCut = usize;
284
285pub trait Segment {
295 type FactIndex: FactIndex;
296 type Command<'a>: Command
297 where
298 Self: 'a;
299
300 fn head(&self) -> Result<Self::Command<'_>, StorageError>;
302
303 fn first(&self) -> Self::Command<'_>;
305
306 fn head_location(&self) -> Location;
308
309 fn first_location(&self) -> Location;
311
312 fn contains(&self, location: Location) -> bool;
314
315 fn policy(&self) -> PolicyId;
317
318 fn prior(&self) -> Prior<Location>;
320
321 fn get_command(&self, location: Location) -> Option<Self::Command<'_>>;
323
324 fn get_by_address(&self, address: Address) -> Option<Location>;
326
327 fn get_from(&self, location: Location) -> Vec<Self::Command<'_>>;
329
330 fn facts(&self) -> Result<Self::FactIndex, StorageError>;
332
333 fn contains_any<I>(&self, locations: I) -> bool
334 where
335 I: IntoIterator,
336 I::Item: AsRef<Location>,
337 {
338 locations
339 .into_iter()
340 .any(|loc| self.contains(*loc.as_ref()))
341 }
342
343 fn shortest_max_cut(&self) -> MaxCut;
347
348 fn longest_max_cut(&self) -> Result<MaxCut, StorageError>;
352
353 fn skip_list(&self) -> &[(Location, MaxCut)];
362}
363
364pub trait FactIndex: Query {}
366
367pub trait Perspective: FactPerspective {
370 fn policy(&self) -> PolicyId;
372
373 fn add_command(&mut self, command: &impl Command) -> Result<usize, StorageError>;
376
377 fn includes(&self, id: CmdId) -> bool;
379
380 fn head_address(&self) -> Result<Prior<Address>, Bug>;
382}
383
384pub trait FactPerspective: QueryMut {}
386
387pub trait Revertable {
390 fn checkpoint(&self) -> Checkpoint;
392
393 fn revert(&mut self, checkpoint: Checkpoint) -> Result<(), Bug>;
395}
396
397pub struct Checkpoint {
399 pub index: usize,
401}
402
403pub trait Query {
410 fn query(&self, name: &str, keys: &[Box<[u8]>]) -> Result<Option<Box<[u8]>>, StorageError>;
412
413 type QueryIterator: Iterator<Item = Result<Fact, StorageError>>;
415
416 fn query_prefix(
421 &self,
422 name: &str,
423 prefix: &[Box<[u8]>],
424 ) -> Result<Self::QueryIterator, StorageError>;
425}
426
427#[derive(Debug, PartialEq, Eq)]
429pub struct Fact {
430 pub key: Keys,
432 pub value: Box<[u8]>,
434}
435
436pub trait QueryMut: Query {
440 fn insert(&mut self, name: String, keys: Keys, value: Box<[u8]>);
444
445 fn delete(&mut self, name: String, keys: Keys);
447}
448
449#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
451pub struct Keys(Box<[Box<[u8]>]>);
452
453impl Deref for Keys {
454 type Target = [Box<[u8]>];
455 fn deref(&self) -> &[Box<[u8]>] {
456 self.0.as_ref()
457 }
458}
459
460impl AsRef<[Box<[u8]>]> for Keys {
461 fn as_ref(&self) -> &[Box<[u8]>] {
462 self.0.as_ref()
463 }
464}
465
466impl core::borrow::Borrow<[Box<[u8]>]> for Keys {
467 fn borrow(&self) -> &[Box<[u8]>] {
468 self.0.as_ref()
469 }
470}
471
472impl From<&[&[u8]]> for Keys {
473 fn from(value: &[&[u8]]) -> Self {
474 value.iter().copied().collect()
475 }
476}
477
478impl Keys {
479 fn starts_with(&self, prefix: &[Box<[u8]>]) -> bool {
480 self.as_ref().starts_with(prefix)
481 }
482}
483
484impl<B: Into<Box<[u8]>>> FromIterator<B> for Keys {
485 fn from_iter<T: IntoIterator<Item = B>>(iter: T) -> Self {
486 Self(iter.into_iter().map(Into::into).collect())
487 }
488}
489
490