pinapod 0.4.0

Zero-copy pod types with derive macros. Alignment-1 representations for zero-overhead data access.
Documentation

PinaPod

PinaPod defines alignment-one, zero-copy representations for Solana account and instruction data. The derive generates the representation, validates bytes before forming references, and keeps the v0.1 wire format.

PinaPod is the Pina-maintained fork of ZeroPod. The crates have independent versions. PinaPod reviews upstream changes before porting them.

Install

[dependencies]
pinapod = "0.2"

PinaPod supports Rust 1.89 and newer. The MSRV follows the Rust versions supported by Solana's Agave releases; see the supported toolchains page for the current alignment and policy. The runtime crate is no_std.

Pick a layout

Use a fixed layout when the account allocation never changes. Bounded strings, vectors, and options work in fixed layouts.

A container reserves its full capacity wherever it appears, so a smaller value never shrinks the representation.

String<32> occupies its one-byte prefix plus all 32 payload bytes, and Vec<u64, 8> occupies its two-byte prefix plus space for all eight elements.

use pinapod::{PinaPod, String, Vec};

#[derive(PinaPod)]
struct Profile {
	authority: [u8; 32],
	display_name: String<32>,
	roles: Vec<u16, 8>,
	note: Option<String<64>>,
}

let mut data = vec![0_u8; Profile::SIZE];
Profile::initialize(&mut data, |profile| {
	profile.display_name.try_set("ifi")?;
	profile.roles.try_set([7_u16, 11])?;
	Ok(())
})?;

let profile = Profile::read_exact(&data)?;
assert_eq!(profile.display_name.as_str(), "ifi");
# Ok::<(), pinapod::PinaPodError>(())

Use a compact layout when the allocation must track active data. Compact schemas store fixed fields in a header and pack active string and vector bytes after that header.

use pinapod::PinaPod;
use pinapod::String;
use pinapod::Vec;

#[derive(PinaPod)]
#[pinapod(compact)]
struct Journal {
    authority: [u8; 32],
    revision: u64,
    entries: Vec<u64, 1024>,
    note: Option<String<128>>,
}

Compact schemas support multiple tails. See the compact account guide for the supported grammar and update API.

Set a prefix width in the type

The schema aliases choose common prefix widths, so ordinary declarations stay short:

  • String<N> is PodString<N, 1>.
  • Vec<T, N> is PodVec<T, N, 2>.

Use the pod types when the wire format needs another width.

PFX is the width in bytes of the length prefix or tag that precedes the payload, and it must be 1, 2, 4, or 8.

The capacity must fit that prefix: String<255> is valid, String<256> is not, and PodString<256, 2> restores it.

use pinapod::PinaPod;
use pinapod::PodString;
use pinapod::PodVec;

#[derive(PinaPod)]
struct Archive {
    label: PodString<300, 2>,
    values: PodVec<u64, 1024, 2>,
}

Do not use #[pinapod(prefix = u16)]. Prefix width belongs in the field type, so the declaration shows the exact wire representation.

Pod types

Type Stored size Meaning
PodU16 through PodU128 2 through 16 bytes Unsigned, little-endian integer
PodI16 through PodI128 2 through 16 bytes Signed, little-endian integer
PodBool 1 byte Boolean with a 0 or 1 byte
PodF32 4 bytes IEEE-754 binary32 stored as its bit pattern
PodF64 8 bytes IEEE-754 binary64 stored as its bit pattern
PodOption<T, PFX> PFX + size_of::<T>() Optional fixed representation
PodString<N, PFX> PFX + N UTF-8 string with at most N bytes
PodVec<T, N, PFX> PFX + N * mapped element size Vector with at most N mapped pod elements

All representations have alignment one, so a stored field can be read at any byte offset without a copy or a relocation.

Safe readers validate tags, lengths, UTF-8, enum discriminants, nested values, and slice bounds before they return a reference.

Features

Feature Adds
fixed Mappings for signed and unsigned fixed 1.30.0 values
floats PodF32/PodF64 and mappings for native f32/f64
solana-address A mapping for solana_address::Address
solana-program-error Conversion from PinaPodError to ProgramError
wincode Canonical SchemaRead and SchemaWrite implementations

No feature is enabled by default, so the core crate stays no_std and dependency-free.

Enable only what a program reads from or writes to the wire.

Documentation and verification

The PinaPod book contains the API guide, the migration guides (v0.1 to v0.2 and v0.2 to v0.3), the safety model, and benchmark instructions. The repository runs native tests on the pinned nightly, current stable, and the MSRV; Miri regressions; Kani proofs including derive-generated compact schemas; coverage-guided fuzzing over every untrusted-input reader (see fuzz/README.md); wire-format fixtures; and a Criterion comparison against both PinaPod v0.1 and upstream ZeroPod. Versions and changelogs are managed by MonoChange, which also provides the semantic-version compatibility check for each release.

Report a suspected soundness or security defect through GitHub private vulnerability reporting. See SECURITY.md for the required report details.

License

Apache-2.0