Skip to main content

sim_kernel/
ref_id.rs

1//! Reference identity: the [`Ref`] contract and its content/handle ids.
2//!
3//! Defines the stable reference types -- content ids, handle ids, and
4//! coordinates -- that name data and objects across the substrate; libraries
5//! resolve refs to values.
6
7use crate::id::Symbol;
8
9/// A stable reference to data or an object across the substrate.
10///
11/// The kernel defines the reference contract; libraries resolve a [`Ref`] to a
12/// concrete value. A ref names its target by symbol, by content id, by a
13/// process-local handle, or by a ranked coordinate.
14#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Ref {
16    /// A named reference resolved through the registry.
17    Symbol(Symbol),
18    /// A content-addressed reference to an immutable datum.
19    Content(ContentId),
20    /// A process-local handle to a live object.
21    Handle(HandleId),
22    /// A ranked coordinate within a named space.
23    Coord(Coordinate),
24}
25
26/// Content-addressed identity: a hash algorithm plus its 32-byte digest.
27#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct ContentId {
29    /// The hash algorithm that produced the digest (for example `core/sha256`).
30    pub algorithm: Symbol,
31    /// The 32-byte content digest.
32    pub bytes: [u8; 32],
33}
34
35impl ContentId {
36    /// Builds a content id from an algorithm symbol and a 32-byte digest.
37    pub fn from_bytes(algorithm: Symbol, bytes: [u8; 32]) -> Self {
38        Self { algorithm, bytes }
39    }
40}
41
42/// Process-local handle to a live object, unique within this process.
43#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct HandleId(pub u128);
45
46impl HandleId {
47    /// Builds a handle from a supplied seed and sequence number.
48    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/// Caller-supplied namespace for a deterministic sequence of live handles.
54///
55/// A runtime boundary obtains this plain value from its bootstrap input. The
56/// kernel never manufactures one from ambient process state.
57#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
58pub struct HandleSeed(pub u64);
59
60impl HandleSeed {
61    /// Creates a handle seed from caller-owned data.
62    pub const fn new(value: u64) -> Self {
63        Self(value)
64    }
65
66    /// Starts a deterministic handle sequence in this seed's namespace.
67    pub const fn sequence(self) -> HandleSequence {
68        HandleSequence {
69            seed: self,
70            next: 1,
71        }
72    }
73}
74
75/// Deterministic allocator for handles in one caller-supplied namespace.
76#[derive(Clone, Debug, PartialEq, Eq)]
77pub struct HandleSequence {
78    seed: HandleSeed,
79    next: u64,
80}
81
82impl HandleSequence {
83    /// Allocates the next handle in the sequence.
84    ///
85    /// # Panics
86    ///
87    /// Panics after exhausting all nonzero `u64` sequence numbers instead of
88    /// wrapping into an existing handle.
89    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/// A ranked coordinate: an ordinal position within a named space.
97#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct Coordinate {
99    /// The named coordinate space.
100    pub space: Symbol,
101    /// The position within the space, keyed by content id.
102    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}