hopper_runtime/ref_only.rs
1//! Compile-proven borrow-guard constraint.
2//!
3//! The type system proves that no raw `&T` / `&mut T` can escape an
4//! account access path.
5//! Every runtime surface already returns a [`Ref`], [`RefMut`],
6//! [`SegRef`], or [`SegRefMut`], but that guarantee is embedded in the
7//! function return types alone. [`HopperRefOnly`] is the nominal
8//! version of that promise: a sealed marker trait implemented only by
9//! Hopper's four borrow guards.
10//!
11//! API authors can now write `fn f<G: HopperRefOnly>(g: G)` and rely
12//! on the compiler to reject a naked `&mut U` at the call site. The
13//! sealed trait pattern means no downstream crate can stamp the marker
14//! onto arbitrary types, which enforces the no-raw-reference
15//! gate at compile time instead of by convention.
16//!
17//! The implementations are explicit for Hopper's four guard types; macros do
18//! not generate additional implementations.
19//!
20//! [`Ref`]: crate::borrow::Ref
21//! [`RefMut`]: crate::borrow::RefMut
22//! [`SegRef`]: crate::segment_lease::SegRef
23//! [`SegRefMut`]: crate::segment_lease::SegRefMut
24
25use crate::borrow::{Ref, RefMut};
26use crate::segment_lease::{SegRef, SegRefMut};
27
28mod sealed {
29 /// Doc-hidden seal. Implementing this for a non-Hopper type would
30 /// require naming `hopper_runtime::ref_only::sealed::Sealed`,
31 /// which this private module makes impossible from outside the
32 /// crate.
33 pub trait Sealed {}
34}
35
36/// Marker trait implemented exclusively by Hopper's four account-data
37/// borrow guards: [`Ref`], [`RefMut`], [`SegRef`], [`SegRefMut`].
38///
39/// Use this as a bound on APIs that must accept only drop-guarded
40/// borrows. A naked `&T` or `&mut T` will fail the bound at compile
41/// time, which is the closure proof for Finding 2 of the audit
42/// ("borrow safety compile-proven, not just runtime-enforced").
43///
44/// [`Ref`]: crate::borrow::Ref
45/// [`RefMut`]: crate::borrow::RefMut
46/// [`SegRef`]: crate::segment_lease::SegRef
47/// [`SegRefMut`]: crate::segment_lease::SegRefMut
48pub trait HopperRefOnly: sealed::Sealed {}
49
50impl<T: ?Sized> sealed::Sealed for Ref<'_, T> {}
51impl<T: ?Sized> sealed::Sealed for RefMut<'_, T> {}
52impl<T: ?Sized> sealed::Sealed for SegRef<'_, T> {}
53impl<T: ?Sized> sealed::Sealed for SegRefMut<'_, T> {}
54
55impl<T: ?Sized> HopperRefOnly for Ref<'_, T> {}
56impl<T: ?Sized> HopperRefOnly for RefMut<'_, T> {}
57impl<T: ?Sized> HopperRefOnly for SegRef<'_, T> {}
58impl<T: ?Sized> HopperRefOnly for SegRefMut<'_, T> {}
59
60#[cfg(test)]
61mod tests {
62 use super::HopperRefOnly;
63
64 fn require_guard<G: HopperRefOnly>() {}
65
66 #[test]
67 fn hopper_guards_satisfy_the_bound() {
68 require_guard::<crate::borrow::Ref<'_, u64>>();
69 require_guard::<crate::borrow::RefMut<'_, u64>>();
70 require_guard::<crate::segment_lease::SegRef<'_, u64>>();
71 require_guard::<crate::segment_lease::SegRefMut<'_, u64>>();
72 }
73}