arkhe_kernel/state/scope.rs
1//! `InstanceScope<'i>` — invariant-lifetime-branded handle to an instance.
2//!
3//! GhostCell pattern (A19): the lifetime `'i` is the type-level brand
4//! preventing `Effect<Authorized, 'i>` of one instance from being passed
5//! to another instance's dispatcher. Production scopes are issued by an
6//! HRTB-bounded `Kernel::with_instance<F>(F: for<'i> ...)` (reserved
7//! / deferred); this module provides the type shape used today via the
8//! skeleton constructor below.
9
10use crate::abi::InstanceId;
11use crate::state::authz::InvariantLifetime;
12use core::marker::PhantomData;
13
14/// Invariant-lifetime-branded handle to an instance (GhostCell pattern,
15/// A19). The lifetime `'i` prevents an `Effect<Authorized, 'i>` of one
16/// instance from being passed to another instance's dispatcher —
17/// the mismatch fails lifetime unification at compile time.
18pub struct InstanceScope<'i> {
19 pub(crate) instance_id: InstanceId,
20 _brand: InvariantLifetime<'i>,
21}
22
23impl<'i> InstanceScope<'i> {
24 /// Test/skeleton constructor — production path is the deferred
25 /// HRTB-bounded `Kernel::with_instance`.
26 #[doc(hidden)]
27 pub fn __new_for_skeleton(instance_id: InstanceId) -> Self {
28 Self {
29 instance_id,
30 _brand: PhantomData,
31 }
32 }
33
34 /// `InstanceId` this scope is branded against.
35 pub fn instance_id(&self) -> InstanceId {
36 self.instance_id
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn scope_carries_instance_id() {
46 let id = InstanceId::new(42).unwrap();
47 let scope: InstanceScope<'_> = InstanceScope::__new_for_skeleton(id);
48 assert_eq!(scope.instance_id().get(), 42);
49 }
50
51 #[test]
52 fn scope_independent_construction_compiles() {
53 // Two scopes constructed in sequence with default elision:
54 // each gets its own lifetime; nothing flows between them.
55 let s1 = InstanceScope::__new_for_skeleton(InstanceId::new(1).unwrap());
56 let s2 = InstanceScope::__new_for_skeleton(InstanceId::new(2).unwrap());
57 assert_eq!(s1.instance_id().get(), 1);
58 assert_eq!(s2.instance_id().get(), 2);
59 // Cross-scope rejection at the dispatcher boundary becomes
60 // type-checkable when the HRTB scope guard ships (deferred).
61 }
62}