#macro

macro perforate

A macro to generate variants of a struct to allow splitting fields for extended periods of time

1 unstable release

0.1.0 May 15, 2024

#1687 in Rust patterns

MIT/Apache

16KB
167 lines

Perforate

Perforate generates variants of a struct to allow a struct field to be "split" from the rest of the struct as in a split borrow.

This is similar in effect to using mem::take or one of the other replacement functions, except it can be performed on fields that don't implement Default or when a suitable placeholer can't be constructed.

Usage

Perforate an owned struct on the stack.

use perforate::Perforate;

#[derive(Perforate)]
#[repr(C)]
pub struct TestStruct {
    #[perforate]
    one: String,
    two: u64,
}

let test_struct = TestStruct{one: "one".to_string(), two: 42};

let (perforated, one) = test_struct.perforate_one();
assert_eq!(core::mem::size_of::<TestStruct>(), core::mem::size_of_val(&perforated));
assert_eq!(perforated.two, 42);
assert_eq!(one, "one");

let original = perforated.replace_perf(one);
assert_eq!(original.two, 42);
assert_eq!(original.one, "one");

Or perforate a struct in an owned box.

use perforate::Perforate;

#[derive(Perforate)]
#[repr(C)]
pub struct TestStruct {
    #[perforate]
    one: String,
    two: u64,
}

let test_struct = Box::new(TestStruct{one: "one".to_string(), two: 42});

let (perforated_box, one) = TestStruct::boxed_perforate_one(test_struct);
assert_eq!(perforated_box.two, 42);
assert_eq!(one, "one");

let original_box = TestStruct::boxed_replace_one(perforated_box, one);
assert_eq!(original_box.two, 42);
assert_eq!(original_box.one, "one");

Caveats

If a struct has generic parameters or lifetimes that are used only by a field marked with the #[perforate] attribute, you must add a PhantomData to your struct to prevent compile errors. In addition, you cannot perforate a field with a generic type parameter on stable until the issue is merged.

You may access the other "unperforated" fields of the perforated struct, however the perforated version of the struct is a new type and does not have any of the trait implementations from its progenitor. This includes a custom Drop trait. So if your struct needs special cleanup behavior you must reassemble it before dropping.

Dependencies

~235–670KB
~16K SLoC