Skip to main content

hopper_runtime/
ref_only.rs

1//! Compile-proven borrow-guard constraint.
2//!
3//! The Hopper Safety Audit's Finding 2 asks for *compile-time* proof
4//! that no raw `&T` / `&mut T` can escape an 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 closes the audit's "prove no raw refs"
15//! gate at compile time instead of by convention.
16//!
17//! # Grep receipt
18//!
19//! An auditor running `grep -r "HopperRefOnly"` sees exactly five
20//! lines: the trait declaration plus the four guard impls. There is
21//! no macro-generated expansion, no procedural indirection. Every
22//! impl is visible at the byte level.
23//!
24//! [`Ref`]: crate::borrow::Ref
25//! [`RefMut`]: crate::borrow::RefMut
26//! [`SegRef`]: crate::segment_lease::SegRef
27//! [`SegRefMut`]: crate::segment_lease::SegRefMut
28
29use crate::borrow::{Ref, RefMut};
30use crate::segment_lease::{SegRef, SegRefMut};
31
32mod sealed {
33    /// Doc-hidden seal. Implementing this for a non-Hopper type would
34    /// require naming `hopper_runtime::ref_only::sealed::Sealed`,
35    /// which this private module makes impossible from outside the
36    /// crate.
37    pub trait Sealed {}
38}
39
40/// Marker trait implemented exclusively by Hopper's four account-data
41/// borrow guards: [`Ref`], [`RefMut`], [`SegRef`], [`SegRefMut`].
42///
43/// Use this as a bound on APIs that must accept only drop-guarded
44/// borrows. A naked `&T` or `&mut T` will fail the bound at compile
45/// time, which is the closure proof for Finding 2 of the audit
46/// ("borrow safety compile-proven, not just runtime-enforced").
47///
48/// [`Ref`]: crate::borrow::Ref
49/// [`RefMut`]: crate::borrow::RefMut
50/// [`SegRef`]: crate::segment_lease::SegRef
51/// [`SegRefMut`]: crate::segment_lease::SegRefMut
52pub trait HopperRefOnly: sealed::Sealed {}
53
54impl<T: ?Sized> sealed::Sealed for Ref<'_, T> {}
55impl<T: ?Sized> sealed::Sealed for RefMut<'_, T> {}
56impl<T: ?Sized> sealed::Sealed for SegRef<'_, T> {}
57impl<T: ?Sized> sealed::Sealed for SegRefMut<'_, T> {}
58
59impl<T: ?Sized> HopperRefOnly for Ref<'_, T> {}
60impl<T: ?Sized> HopperRefOnly for RefMut<'_, T> {}
61impl<T: ?Sized> HopperRefOnly for SegRef<'_, T> {}
62impl<T: ?Sized> HopperRefOnly for SegRefMut<'_, T> {}
63
64#[cfg(test)]
65mod tests {
66    use super::HopperRefOnly;
67
68    fn require_guard<G: HopperRefOnly>() {}
69
70    #[test]
71    fn hopper_guards_satisfy_the_bound() {
72        require_guard::<crate::borrow::Ref<'_, u64>>();
73        require_guard::<crate::borrow::RefMut<'_, u64>>();
74        require_guard::<crate::segment_lease::SegRef<'_, u64>>();
75        require_guard::<crate::segment_lease::SegRefMut<'_, u64>>();
76    }
77}