@@ -45,29 +45,32 @@ struct Slice<'a, T> {
4545
4646Use ` PhantomData ` to prevent mixing values from different "sessions" or "contexts":
4747
48- ``` rust
48+ This example intentionally fails to compile at the cross-arena lookup, even when
49+ the handle is allocated inside the inner closure:
50+
51+ ``` rust,compile_fail,E0521
4952use std::cell::RefCell;
5053use std::marker::PhantomData;
5154
5255/// A handle branded to a specific arena instance.
53- /// Invariant over 'arena — prevents using a handle from one arena with another.
5456struct ArenaHandle<'arena> {
5557 index: usize,
56- _brand : PhantomData <* mut & 'arena ()>,
58+ _phantom : PhantomData<&'arena ()>,
5759}
5860
5961/// An arena that brands each handle with its unique lifetime.
62+ /// Invariant over 'arena — prevents shortening the brand to match another arena.
6063struct Arena<'arena> {
6164 data: RefCell<Vec<String>>,
62- _phantom : PhantomData <& 'arena ()>,
65+ _brand : PhantomData<*mut &'arena ()>,
6366}
6467
6568/// Create an arena and pass it to a closure.
6669/// Each call gets a unique, opaque lifetime that can't be forged.
6770fn with_arena<R>(f: impl for<'arena> FnOnce(&Arena<'arena>) -> R) -> R {
6871 let arena = Arena {
6972 data: RefCell::new(Vec::new()),
70- _phantom : PhantomData ,
73+ _brand : PhantomData,
7174 };
7275 f(&arena)
7376}
@@ -78,7 +81,7 @@ impl<'arena> Arena<'arena> {
7881 let mut data = self.data.borrow_mut();
7982 let index = data.len();
8083 data.push(value);
81- ArenaHandle { index , _brand : PhantomData }
84+ ArenaHandle { index, _phantom : PhantomData }
8285 }
8386
8487 /// Look up by handle — only accepts handles from THIS arena
@@ -90,17 +93,23 @@ impl<'arena> Arena<'arena> {
9093
9194fn main() {
9295 with_arena(|arena1| {
93- let handle1 = arena1 . alloc (" hello" . to_string ());
94- println! (" {}" , arena1 . get (& handle1 )); // ✅
96+ with_arena(|arena2| {
97+ let handle1 = arena1.alloc("hello".to_string());
98+ println!("{}", arena1.get(&handle1)); // ✅
9599
96- // Can't use handle1 with a different arena — compile-time error
97- // with_arena(|arena2| {
98- // arena2.get(&handle1); // ❌ borrowed data escapes outside of closure
99- // });
100+ // Can't use handle1 with a different arena — compile-time error
101+ arena2.get(&handle1); // ❌ borrowed data escapes outside of closure
102+ });
100103 });
101104}
102105```
103106
107+ The arena must be ** invariant** over ` 'arena ` : otherwise, a shared reference to an
108+ outer arena can be shortened to an inner arena's brand. Making only the handle
109+ invariant is not enough — allocating from the outer arena inside the inner closure
110+ can then produce a handle with the inner brand. ` PhantomData<*mut &'arena ()> `
111+ fixes the arena's brand, while the handle can remain covariant.
112+
104113### Unit-of-Measure Pattern
105114
106115Prevent mixing incompatible units at compile time, with zero runtime cost:
@@ -404,4 +413,3 @@ fn main() {
404413</details >
405414
406415***
407-
0 commit comments