nearest/near.rs
1use std::{fmt, marker::PhantomData, num::NonZero, ops::Deref};
2
3use crate::{Flat, Patch, emitter::Pos};
4
5/// A self-relative pointer stored as a 4-byte `NonZero<i32>` offset.
6///
7/// # Layout
8///
9/// `#[repr(C)]` — 4 bytes, `align_of::<i32>()` alignment:
10///
11/// | Offset | Field | Type |
12/// |--------|-------|----------------|
13/// | 0 | `off` | `NonZero<i32>` |
14///
15/// The offset is relative to the address of `off` itself (not the start of
16/// the region). Non-zero guarantee ensures `Near<T>` never points to itself.
17///
18/// `Near<T>` is **not** `Copy` or `Clone` — moving it would invalidate the
19/// self-relative offset. Use it only inside [`Region`](crate::Region) buffers
20/// built by the emitter.
21///
22/// # Soundness
23///
24/// **Provenance recovery**: [`get`](Self::get) computes the target address by
25/// adding the stored `i32` offset to the address of the offset field itself.
26/// Because `&self.off` has provenance over only 4 bytes (insufficient for the
27/// target `T`), the method uses `with_exposed_provenance` to recover the
28/// full allocation's provenance — previously exposed by `AlignedBuf::grow`.
29/// Miri validates this pattern with no UB detected.
30///
31/// **Non-zero invariant**: The offset is `NonZero<i32>`, so a `Near<T>` can
32/// never point to itself (offset 0). This is enforced by the emitter's
33/// `patch_near` method which panics on `target == at`.
34pub struct Near<T> {
35 off: NonZero<i32>,
36 _type: PhantomData<T>,
37}
38
39// SAFETY: Near contains only a NonZero<i32> and PhantomData — no Drop, no heap.
40// Unconditional impl: Near<T> is always Flat regardless of T, since it stores only
41// an offset, not an actual T. This avoids circular trait bounds in recursive types.
42unsafe impl<T> Flat for Near<T> {
43 unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
44 // SAFETY: Caller guarantees `at` was allocated for `Near<T>`.
45 // Byte-copy the 4-byte offset. Containing struct's deep_copy handles pointer following.
46 unsafe {
47 p.write_bytes(at, std::ptr::from_ref(self).cast(), size_of::<Self>());
48 }
49 }
50}
51
52impl<T: Flat> Near<T> {
53 /// Resolve the self-relative offset to a reference.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use nearest::{Flat, Near, Region};
59 ///
60 /// #[derive(Flat, Debug)]
61 /// struct Wrapper { inner: Near<u32> }
62 ///
63 /// let region = Region::new(Wrapper::make(42u32));
64 /// assert_eq!(*region.inner.get(), 42);
65 ///
66 /// // Deref also works (Near<T> implements Deref<Target = T>).
67 /// assert_eq!(*region.inner, 42);
68 /// ```
69 #[must_use]
70 pub fn get(&self) -> &T {
71 // SAFETY: The offset was written by `Emitter::patch_near` which guarantees
72 // the target lies within the same `Region` buffer. The region keeps the
73 // buffer alive and properly aligned for `T`.
74 //
75 // Strict provenance is not possible here: `&self.off` has provenance over
76 // only 4 bytes, but `T` may live anywhere in the buffer. A derived pointer
77 // (e.g. `wrapping_byte_offset`) would fail Stacked Borrows retagging when
78 // the target `&T` is larger than 4 bytes.
79 //
80 // Instead, `with_exposed_provenance` recovers the full allocation's
81 // provenance (exposed by `AlignedBuf::grow`). This triggers Miri
82 // int-to-ptr cast warnings but is not UB.
83 unsafe {
84 let base = std::ptr::from_ref(&self.off).cast::<u8>();
85 let target = base.addr().wrapping_add_signed(self.off.get() as isize);
86 &*std::ptr::with_exposed_provenance::<T>(target)
87 }
88 }
89}
90
91impl<T: Flat> Deref for Near<T> {
92 type Target = T;
93
94 fn deref(&self) -> &T {
95 self.get()
96 }
97}
98
99impl<T: Flat + fmt::Debug> fmt::Debug for Near<T> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 fmt::Debug::fmt(self.get(), f)
102 }
103}