Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pod_collections_and_refactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
pina_pod_primitives: minor
---

Add `PodOption<T>`, `PodString<N, PFX>`, and `PodVec<T, N, PFX>` fixed-capacity collection types for zero-copy Solana account layouts. Split the monolithic `lib.rs` into a multi-file module structure for maintainability. Add kani proof harnesses for collection types.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ level = "warn"
check-cfg = [
'cfg(target_os, values("solana"))',
'cfg(target_feature, values("static-syscalls"))',
'cfg(kani)',
]

[workspace.lints.clippy]
Expand Down
42 changes: 42 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@

All notable changes to this project will be documented in this file.

## Unreleased

### Features

#### Add PodOption, PodString, and PodVec collection types (pina_pod_primitives)

Fixed-capacity, alignment-1 collection types for zero-copy Solana account layouts:

- `PodOption<T: Pod>` — fixed-size optional with 1-byte discriminant
- `PodString<N, PFX=1>` — fixed-capacity string with length prefix
- `PodVec<T: Pod, N, PFX=2>` — fixed-capacity vector with length prefix

All implement `bytemuck::Pod` + `bytemuck::Zeroable`. Overflow returns `PodCollectionError`.

New mdt providers:

- `podCollectionTypesTable` — collection types reference table
- `podCollectionDescription` — collection type semantics

Updated documentation:

- `pina_pod_primitives/readme.md` — added collection types section
- `docs/src/core-concepts.md` — added Pod collection types section
- `docs/src/crates-and-features.md` — added collection types and description
- `readme.md` — added Pod collection types section
- Updated `podTypesTable` and `podArithmeticDescription` providers to clarify integer-only scope

### Refactoring

#### Split `pina_pod_primitives/lib.rs` into multi-file module structure

The monolithic `lib.rs` (2322 lines) was split into focused modules:

- `pod_bool.rs` — PodBool type
- `pod_numeric.rs` — PodU16..PodI128 via macros
- `macros.rs` — define_pod_unsigned!/define_pod_signed! etc.
- `error.rs` — PodCollectionError
- `option.rs` — PodOption + kani proofs
- `string.rs` — PodString + kani proofs
- `vec.rs` — PodVec + kani proofs
- `tests/` — unit tests per type

## 0.8.0 (2026-03-30)

### Breaking Changes
Expand Down
32 changes: 28 additions & 4 deletions crates/pina_pod_primitives/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

<br>

Alignment-safe primitive POD wrappers used by Pina and generated Codama Rust clients.
Alignment-safe primitive POD wrappers and fixed-capacity collection types used by Pina and generated Codama Rust clients.

[![Crates.io][crate-image]][crate-link] [![Docs.rs][docs-image]][docs-link] [![CI][ci-status-image]][ci-status-link] [![License][unlicense-image]][unlicense-link] [![codecov][codecov-image]][codecov-link]

This crate provides `PodBool`, `PodU16`, `PodI16`, `PodU32`, `PodI32`, `PodU64`, `PodI64`, `PodU128`, and `PodI128` for use in `#[repr(C)]` zero-copy layouts.
This crate provides `PodBool`, `PodU16`, `PodI16`, `PodU32`, `PodI32`, `PodU64`, `PodI64`, `PodU128`, and `PodI128` for use in `#[repr(C)]` zero-copy layouts, plus fixed-capacity collection types `PodOption<T>`, `PodString<N, PFX>`, and `PodVec<T, N, PFX>`.

## Arithmetic

<!-- {=podArithmeticDescription} -->

Arithmetic operators (`+`, `-`, `*`) use **wrapping** semantics in release builds for CU efficiency and **panic on overflow** in debug builds. Use `checked_add`, `checked_sub`, `checked_mul`, `checked_div` where overflow must be detected in all build profiles.
Arithmetic operators (`+`, `-`, `*`) on Pod **integer** types use **wrapping** semantics in release builds for CU efficiency and **panic on overflow** in debug builds. Use `checked_add`, `checked_sub`, `checked_mul`, `checked_div` where overflow must be detected in all build profiles.

Each Pod integer type provides `ZERO`, `MIN`, and `MAX` constants.

Expand All @@ -26,7 +26,7 @@ Each Pod integer type provides `ZERO`, `MIN`, and `MAX` constants.
cargo add pina_pod_primitives
```

## Types
## Integer types

<br>

Expand All @@ -48,6 +48,30 @@ All types are `#[repr(transparent)]` over byte arrays (or `u8` for `PodBool`) an

<!-- {/podTypesTable} -->

## Collection types

<br>

<!-- {=podCollectionTypesTable} -->

| Type | Purpose | Layout |
| -------------------------- | ---------------------- | ----------------------------------------- |
| `PodOption<T: Pod>` | Fixed-size `Option<T>` | 1-byte discriminant + `T` |
| `PodString<N, PFX=1>` | Fixed-capacity string | `PFX`-byte length prefix + `N` data bytes |
| `PodVec<T: Pod, N, PFX=2>` | Fixed-capacity vec | `PFX`-byte length prefix + `N` elements |

All collection types are `#[repr(C)]`, alignment-1, and implement `bytemuck::Pod` + `bytemuck::Zeroable`. Length prefixes (`PFX`) default to 1 byte for strings (max 255) and 2 bytes for vectors (max 65 535 elements).

<!-- {/podCollectionTypesTable} -->

<!-- {=podCollectionDescription} -->

Collection types store data inline with a length prefix, enabling zero-copy access inside `#[repr(C)]` account structs. Overflow is detected at insertion time — `try_set` / `try_push` return `Err(PodCollectionError::Overflow)` when capacity is exceeded.

`PodString` provides UTF-8 validation via `try_as_str()`, while `PodVec` offers slice-based access via `as_slice()` / `as_mut_slice()`. `PodOption` mirrors the `Option<T>` API with `get()`, `set()`, and `clear()`.

<!-- {/podCollectionDescription} -->

[crate-image]: https://img.shields.io/crates/v/pina_pod_primitives.svg?style=flat-square
[crate-link]: https://crates.io/crates/pina_pod_primitives
[docs-image]: https://docs.rs/pina_pod_primitives/badge.svg
Expand Down
35 changes: 35 additions & 0 deletions crates/pina_pod_primitives/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! Error type for Pod collection operations.

use core::fmt;

/// Error type for collection operations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PodCollectionError {
/// Value exceeds capacity.
Overflow,
/// Invalid UTF-8 in string data.
InvalidUtf8,
/// Index out of bounds.
OutOfBounds,
}

impl fmt::Display for PodCollectionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Overflow => write!(f, "value exceeds capacity"),
Self::InvalidUtf8 => write!(f, "invalid UTF-8"),
Self::OutOfBounds => write!(f, "index out of bounds"),
}
}
}

/// Returns the maximum `N` value representable by a `PFX`-byte length prefix.
pub(crate) const fn max_n_for_pfx(pfx: usize) -> usize {
match pfx {
1 => u8::MAX as usize,
2 => u16::MAX as usize,
4 => u32::MAX as usize,
8 => usize::MAX,
_ => 0,
}
}
Loading
Loading