1use crate::id::Symbol;
8
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Ref {
16 Symbol(Symbol),
18 Content(ContentId),
20 Handle(HandleId),
22 Coord(Coordinate),
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct ContentId {
29 pub algorithm: Symbol,
31 pub bytes: [u8; 32],
33}
34
35impl ContentId {
36 pub fn from_bytes(algorithm: Symbol, bytes: [u8; 32]) -> Self {
38 Self { algorithm, bytes }
39 }
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct HandleId(pub u128);
45
46impl HandleId {
47 pub const fn from_seed_and_sequence(seed: HandleSeed, sequence: u64) -> Self {
49 Self(((seed.0 as u128) << 64) | sequence as u128)
50 }
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
58pub struct HandleSeed(pub u64);
59
60impl HandleSeed {
61 pub const fn new(value: u64) -> Self {
63 Self(value)
64 }
65
66 pub const fn sequence(self) -> HandleSequence {
68 HandleSequence {
69 seed: self,
70 next: 1,
71 }
72 }
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
77pub struct HandleSequence {
78 seed: HandleSeed,
79 next: u64,
80}
81
82impl HandleSequence {
83 pub fn next_handle(&mut self) -> HandleId {
90 let sequence = self.next;
91 self.next = self.next.checked_add(1).expect("handle sequence exhausted");
92 HandleId::from_seed_and_sequence(self.seed, sequence)
93 }
94}
95
96#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct Coordinate {
99 pub space: Symbol,
101 pub ordinal: ContentId,
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 fn content_id(byte: u8) -> ContentId {
110 ContentId::from_bytes(Symbol::qualified("core", "sha256"), [byte; 32])
111 }
112
113 #[test]
114 fn ref_id_equal_symbols_compare_equal() {
115 let left = Ref::Symbol(Symbol::qualified("core", "Bool"));
116 let right = Ref::Symbol(Symbol::qualified("core", "Bool"));
117
118 assert_eq!(left, right);
119 }
120
121 #[test]
122 fn ref_id_equal_content_ids_compare_equal() {
123 let left = content_id(1);
124 let right = content_id(1);
125
126 assert_eq!(left, right);
127 }
128
129 #[test]
130 fn ref_id_equal_coordinates_compare_equal() {
131 let left = Coordinate {
132 space: Symbol::qualified("rank", "natural"),
133 ordinal: content_id(2),
134 };
135 let right = Coordinate {
136 space: Symbol::qualified("rank", "natural"),
137 ordinal: content_id(2),
138 };
139
140 assert_eq!(left, right);
141 }
142
143 #[test]
144 fn ref_id_handle_never_equals_content_id() {
145 let handle = Ref::Handle(HandleSeed::new(7).sequence().next_handle());
146 let content = Ref::Content(content_id(3));
147
148 assert_ne!(handle, content);
149 }
150
151 #[test]
152 fn equal_seeds_produce_identical_handle_sequences() {
153 let mut left = HandleSeed::new(7).sequence();
154 let mut right = HandleSeed::new(7).sequence();
155
156 assert_eq!(left.next_handle(), right.next_handle());
157 assert_eq!(left.next_handle(), right.next_handle());
158 }
159
160 #[test]
161 fn distinct_seeds_separate_handle_sequences() {
162 let mut left = HandleSeed::new(7).sequence();
163 let mut right = HandleSeed::new(8).sequence();
164
165 assert_ne!(left.next_handle(), right.next_handle());
166 assert_ne!(left.next_handle(), right.next_handle());
167 }
168}