Skip to main content

Crate ostd_pod

Crate ostd_pod 

Source
Expand description

§ostd-pod

A trait and macros for Plain Old Data (POD) types.

This crate provides the Pod trait, which marks types that can be safely converted to and from arbitrary byte sequences. It’s built on top of the mature zerocopy crate to ensure type safety.

§Features

  • Safe Byte Conversion: POD types can be safely converted to byte sequences and created from byte sequences.
  • Based on zerocopy: Built on top of the zerocopy crate for type safety guarantees.
  • Derive Macro Support: Provides #[derive(Pod)] to simplify POD type definitions.
  • Union Support: Supports union types via the #[pod_union] macro.
  • Automatic Padding Management: Automatically handles padding bytes through the #[padding_struct] macro.

§What is a POD Type?

A POD (Plain Old Data) type is a type that can be safely converted to and from an arbitrary byte sequence. For example, primitive types like u8 and i16 are POD types; yet, bool is not a POD type. A struct whose fields are POD types is also considered a POD. A union whose fields are all POD types is also a POD. The memory layout of any POD type is #[repr(C)].

§Quick Start

§Step 1: Edit your Cargo.toml

Add these dependencies to your Cargo.toml.

[dependencies]
ostd-pod = "0.2.0"
zerocopy = { version = "0.8.34", features = ["derive" ] }

zerocopy must be explicitly specified as a dependency because ostd-pod relies on its procedural macros, which expand to compile-time checks that reference internal zerocopy types hardcoded to the zerocopy crate name.

§Step 2: Edit your lib.rs (or main.rs)

Insert the following lines to your lib.rs or main.rs:

#[macro_use]
extern crate ostd_pod;

We import the ostd_pod crate with extern and #[macro_use] for the convenience of having Rust’s built-in derive attribute macro globally overridden by the custom derive attribute macro provided by this crate. This custom derive macro is needed because the Pod trait cannot be derived in the regular way as other traits.

§Step 3: Define your first POD type

Now we can define a POD struct that can be converted to and from any byte sequence of the same size.

#[macro_use]
extern crate ostd_pod;
use ostd_pod::{IntoBytes, FromBytes, Pod};

#[repr(C)]
#[derive(Pod, Clone, Copy, Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 10, y: 20 };

    // Convert to bytes
    let bytes = point.as_bytes();
    assert_eq!(bytes, &[10, 0, 0, 0, 20, 0, 0, 0]);

    // Create from bytes
    let point2 = Point::from_bytes(bytes);
    assert_eq!(point, point2);
}

§Advanced Usage

§Use POD Unions

Union fields cannot be accessed safely because we cannot know which variant is currently active. To address this, we provide a pod_union macro that enables safe access to union fields.

#[macro_use]
extern crate ostd_pod;
use ostd_pod::{FromZeros, IntoBytes};

#[pod_union]
#[derive(Copy, Clone)]
#[repr(C)]
union Data {
    value: u64,
    bytes: [u8; 4],
}

fn main() {
    let mut data = Data::new_value(0x1234567890ABCDEF);

    // Access the same memory through different fields
    assert_eq!(*data.value(), 0x1234567890ABCDEF);
    assert_eq!(*data.bytes(), [0xEF, 0xCD, 0xAB, 0x90]);
}

§Automatic Padding Handling

When a struct has fields with different sizes, there may be implicit padding bytes between fields. The padding_struct macro automatically inserts explicit padding fields so the struct can be safely used as a POD type.

#[macro_use]
extern crate ostd_pod;
use ostd_pod::IntoBytes;

#[repr(C)]
#[padding_struct]
#[derive(Pod, Clone, Copy, Debug, Default)]
struct PackedData {
    a: u8,
    // `padding_struct` automatically inserts 3 bytes of padding here
    b: u32,
    c: u16,
    // `padding_struct` automatically inserts 2 bytes of padding here
}

fn main() {
    let data = PackedData {
        a: 1,
        b: 2,
        c: 3,
        ..Default::default()
    };

    // Can safely convert to bytes, padding bytes are explicitly handled
    let bytes = data.as_bytes();
    assert_eq!(bytes.len(), 12);
    assert_eq!(bytes, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]);
}

§License

This project is licensed under MPL-2.0.

Modules§

array_helper
Aligned array helpers for Pod types.

Traits§

FromBytes
Types for which any bit pattern is valid.
FromZeros
Types for which a sequence of 0 bytes is a valid instance.
Immutable
Types which are free from interior mutability.
IntoBytes
Types that can be converted to an immutable slice of initialized bytes.
KnownLayout
Indicates that zerocopy can reason about certain aspects of a type’s layout.
Pod
A trait for plain old data (POD).

Attribute Macros§

derive
An attribute macro that replaces #[derive(Pod)] with the corresponding zerocopy traits.
padding_struct
Procedural macro to automatically add padding fields to a #[repr(C)] struct.
pod_union
An attribute macro that enables safe usage of unions as POD types.

Derive Macros§

FromBytes
FromZeros
Immutable
IntoBytes
KnownLayout