Skip to main content

Module pod

Module pod 

Source
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:

  1. Every [u8; size_of::<T>()] byte pattern represents a valid T. No “niches”, no enum-discriminant invariants, no bool-style forbidden bit patterns.
  2. align_of::<T>() == 1, the type can be read from any byte offset of an account buffer without alignment fault.
  3. T contains no padding (#[repr(C)] with alignment-1 fields, or #[repr(transparent)] over a Pod type).
  4. T contains no internal pointers / references, overlay always yields data that’s safe to Copy.

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 T on raw account bytes at any offset.
ValuePod
Marker for Copy + Sized scalars/arrays that may be read by value from raw bytes with read_unaligned_value (alignment-independent).
Zeroable
Marker for Copy + Sized values that are valid for every bit pattern.

Functions§

read_unaligned_value
Read a ValuePod scalar/array out of bytes at offset by value, tolerating any alignment (uses core::ptr::read_unaligned).