Crates.io | pstruct |
lib.rs | pstruct |
version | |
source | src |
created_at | 2024-12-08 23:36:44.959759 |
updated_at | 2024-12-09 03:31:12.777192 |
description | A Rust procedural macro for generating pointer struct implementations with field offset access. |
homepage | |
repository | https://github.com/ehuff700/pstruct |
max_upload_size | |
id | 1476834 |
Cargo.toml error: | TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
A Rust procedural macro for generating pointer struct implementations with field offset access. The purpose of this crate is to minimize stack space, preventing struct copies1, while still allowing ergonomic field access. This macro abstracts away a lot of the pain of interacting with pointers to structs, such as casting, pointer arithmetic, transmutation, etc.
A big inspiration for need for this crate was minimizing stack space for functions which use WinAPI structs, as they are often massive in size.
Add this to your Cargo.toml
:
[dependencies]
pstruct = "0.1.0"
use pstruct::p_struct;
// Define a byte array to simulate struct data
let byte_array: &[u8] = &[
69, // `field_b` (offset 0)
255, 255, 255, 255, // `field_a` (offset 1)
10, 20, 30, 40, 50, 60, 70, 80, 90, 100, // `field_d` (offset 5)
40, // `field_c` (offset 0xF)
];
// Define a pointer struct using the macro
p_struct! {
pub struct Example {
#[offset(0x1)]
field_a: u32,
#[offset(0x0)]
field_b: u8,
#[offset(0xF, reinterpret)]
field_c: *const u8,
#[offset(0x5, array(10))]
field_d: *const u8,
}
}
let example_ptr = PExample::from(byte_array);
// Access fields
unsafe {
assert_eq!(example_ptr.field_b(), 69);
assert_eq!(example_ptr.field_a(), u32::MAX);
// Array access
let field_d_1 = example_ptr.get_field_d(0).unwrap();
assert_eq!(*field_d_1, 10u8);
// Reconstruct array
let array = core::slice::from_raw_parts(example_ptr.field_d(), 10);
assert_eq!(array, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
// Reinterpreted pointer
assert_eq!(*(example_ptr.field_c().as_ref().unwrap()), 40u8);
}
offset
The main attribute for specifying field offsets and behavior:
#[offset(0x1)]
- Specifies the offset from base address#[offset(0x1, reinterpret)]
- Reinterprets the pointer at the given offset as another pointer type.#[offset(0x1, array(size))]
- Defines an array of pointers and generates a getter method for indexing into the array.This crate involves heavy unsafe operations when accessing fields. Consumers of this crate are responsible for:
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
1 You could always use references to prevent the copy, but this still doesn't solve the problem of manually defining structs with padding bytes which gets very tedious and is very common for those working with WinAPI (PEB, TEB, etc).