Expand description
Pod, the canonical runtime-layer “safe to interpret from raw bytes” marker.
Hopper’s typed access primitives (segment_ref, segment_mut,
raw_ref, raw_mut, read_data) all overlay a T on a slice of
account bytes. That overlay is only sound if every bit pattern of
the right size decodes to a valid T and the type has alignment 1
(so the offset within the BPF input buffer is always valid for T).
Requiring only T: Copy is too loose: bool, char, references,
and structs with padding are all
Copy + Sized but not safe to overlay on raw bytes. This module
carries the tightened marker.
§Contract
Implementing Pod for a type T asserts all of:
- Every
[u8; size_of::<T>()]byte pattern represents a validT. No “niches”, no enum-discriminant invariants, nobool-style forbidden bit patterns. align_of::<T>() == 1, the type can be read from any byte offset of an account buffer without alignment fault.Tcontains no padding (#[repr(C)]with alignment-1 fields, or#[repr(transparent)]over aPodtype).Tcontains no internal pointers / references, overlay always yields data that’s safe toCopy.
Hopper’s higher-layer macros (#[hopper::state], #[hopper::pod],
hopper_layout!) enforce these conditions at compile time and emit
the derived unsafe impl Pod. Hand-authored layouts opt in via
unsafe impl Pod for MyLayout {}.
§Compile-fail demonstration
The following misuse patterns are rejected at compile time. Hopper’s
Pod + Zeroable proof layer enforces field-level validity during macro
expansion, so every zero-copy access path rejects them automatically.
bool is not Pod (the bit patterns 0x02..=0xFF don’t decode to
a valid bool):
let _ = account.segment_ref::<bool>(borrows, 16, 1);char is not Pod (valid Unicode scalar values form a sparse set):
let _ = account.segment_ref::<char>(borrows, 16, 4);A #[repr(C)] struct with implicit padding is not Pod because the
padding bytes would be part of the raw overlay contract:
#[derive(Copy, Clone)]
#[repr(C)]
struct Padded {
a: u8,
// implicit 7 bytes of padding to align b
b: u64,
}
let _ = account.segment_ref::<Padded>(borrows, 16, 16);A type-level user mis-spelling unsafe impl Pod for Padded {} can
still opt into an unsafe contract manually, but Hopper’s macro entry
points reject that layout before emitting the impl.
A well-formed primitive or wire type is accepted:
let _: Result<hopper_runtime::SegRef<'_, [u8; 8]>, _> =
account.segment_ref::<[u8; 8]>(borrows, 16, 8);§Trait identity across layers
Hopper re-exports hopper_native::Pod as the single Pod trait for the
stack. One unsafe impl Pod for MyStruct {} unlocks every Hopper access API
from the lowest-level AccountView::raw_mut up to #[hopper::state]-
generated accessors, across all crates, with no orphan-rule gymnastics.
Traits§
- Pod
- Marker for types that can be safely overlaid as
&T/&mut Ton raw account bytes at any offset. - Value
Pod - Marker for
Copy + Sizedscalars/arrays that may be read by value from raw bytes withread_unaligned_value(alignment-independent). - Zeroable
- Marker for
Copy + Sizedvalues that are valid for every bit pattern.
Functions§
- read_
unaligned_ value - Read a
ValuePodscalar/array out ofbytesatoffsetby value, tolerating any alignment (usescore::ptr::read_unaligned).