Oregami
Repositories/oxedyne/ore

oxedyne/ore/oracle/src/id.rs

3.7 KiB, 1 run

created by r2848102244:79, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! The three identifier spaces of design note section 4.1.
2//!
3//! Only operation ids are minted. Content ids and placement ids are computed
4//! by arithmetic from an operation id and an offset, exactly as the note
5//! specifies, so that nothing in this prototype ever mints an identifier for a
6//! fragment.
7
8use oxedyne_fe2o3_core::prelude::*;
9
10/// An operation identity, and simultaneously a Lamport timestamp.
11///
12/// The field order is deliberate: the derived `Ord` is the note's **op order**,
13/// `(counter, replica)` ascending, which is the total order used for every
14/// tie-break in the design.
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
16pub struct OpId {
17 /// Lamport counter.
18 pub counter: u64,
19 /// Originating replica.
20 pub replica: u32,
21}
22
23impl OpId {
24 /// Creates an operation id.
25 pub fn new(counter: u64, replica: u32) -> Self {
26 Self { counter, replica }
27 }
28}
29
30impl std::fmt::Display for OpId {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}:{}", self.replica, self.counter)
33 }
34}
35
36/// Byte `off` of the run inserted by operation `op`. Written `⟨r:c⟩+k` in the
37/// design note. Never minted, only computed.
38#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
39pub struct ContentId {
40 /// The splice that created the byte.
41 pub op: OpId,
42 /// Offset within that splice's inserted run.
43 pub off: u32,
44}
45
46impl ContentId {
47 /// Creates a content id.
48 pub fn new(op: OpId, off: u32) -> Self {
49 Self { op, off }
50 }
51}
52
53impl std::fmt::Display for ContentId {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(f, "<{}>+{}", self.op, self.off)
56 }
57}
58
59/// A half-open run `[from, to)` of content ids sharing one creating operation.
60#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
61pub struct ContentRange {
62 /// The splice that created the bytes.
63 pub op: OpId,
64 /// First offset, inclusive.
65 pub from: u32,
66 /// Last offset, exclusive.
67 pub to: u32,
68}
69
70impl ContentRange {
71 /// Creates a content range.
72 pub fn new(op: OpId, from: u32, to: u32) -> Outcome<Self> {
73 if to < from {
74 return Err(err!("Empty or inverted content range {}..{}", from, to; Invalid, Input));
75 }
76 Ok(Self { op, from, to })
77 }
78
79 /// Length in bytes.
80 pub fn len(&self) -> u32 {
81 self.to - self.from
82 }
83
84 /// Whether the range is empty.
85 pub fn is_empty(&self) -> bool {
86 self.to == self.from
87 }
88
89 /// Whether the range contains the given content id.
90 pub fn contains(&self, cid: &ContentId) -> bool {
91 cid.op == self.op && cid.off >= self.from && cid.off < self.to
92 }
93
94 /// Whether two ranges share at least one content id.
95 pub fn intersects(&self, other: &Self) -> bool {
96 self.op == other.op && self.from < other.to && other.from < self.to
97 }
98
99 /// Iterates the content ids of the range.
100 pub fn ids(&self) -> impl Iterator<Item = ContentId> + '_ {
101 let op = self.op;
102 (self.from..self.to).map(move |off| ContentId::new(op, off))
103 }
104}
105
106impl std::fmt::Display for ContentRange {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 write!(f, "<{}>+{}..{}", self.op, self.from, self.to)
109 }
110}
111
112/// Which side of a content id an anchor binds to.
113#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
114pub enum Side {
115 /// The gap immediately preceding the byte.
116 Before,
117 /// The gap immediately following the byte.
118 After,
119}
120
121/// A Fugue origin. `None` means the start or end of the file.
122pub type Anchor = Option<(ContentId, Side)>;
123
124/// Convenience: an anchor immediately after a byte, the normal form for a left
125/// origin.
126pub fn after(cid: ContentId) -> Anchor {
127 Some((cid, Side::After))
128}
129
130/// Convenience: an anchor immediately before a byte, the normal form for a
131/// right origin.
132pub fn before(cid: ContentId) -> Anchor {
133 Some((cid, Side::Before))
134}