| Crates.io | placid |
| lib.rs | placid |
| version | 0.1.0 |
| created_at | 2026-01-11 10:40:02.521202+00 |
| updated_at | 2026-01-11 10:40:02.521202+00 |
| description | Separated ownership and in-place construction in Rust |
| homepage | |
| repository | https://github.com/js2xxx/placid |
| max_upload_size | |
| id | 2035528 |
| size | 209,570 |
placid - Separated ownership and in-place constructionplacid extends Rust's ownership model with owned and uninit references with pinning variants (semantically &own T, &uninit T, and &pin own T or Pin<&own T>). It also provides macros, traits, and functions for constructing and manipulating these types, achieving safe in-place construction.
In Rust, the ownership of a value is typically bound to the value itself. In other words, there is no way to separate the ownership of a value from it.
This creates challenges in scenarios where:
memcpys;Traditional Rust forces you to construct values on the stack, then move them, which can be inefficient for large types. placid solves this by introducing owned and uninit references that carry full ownership through a reference.
Owned References (&own T): Carry exclusive ownership through a reference.
Pinned Owned References (&pin own T): Combine ownership with pinning guarantees for immovable types.
In-place Construction: Construct complex types directly in their final location using init! and init_pin! macros.
Uninit References: Work safely with uninitialized memory.
Safe Movement: Transfer ownership out of smart pointers like Box without reallocating or moving the underlying data.
Add placid to your Cargo.toml:
[dependencies]
placid = "<the current version>"
Constructing an owned reference directly on the stack:
use placid::{Own, own, Init, init};
let simple = own!(42);
assert_eq!(*simple, 42);
#[derive(Init)]
struct LargeData {
buffer: [u8; 1024],
}
fn process_owned(data: Own<LargeData>) {
// The function owns the data and will drop it when done.
println!("Processing: {} bytes", std::mem::size_of_val(&*data));
} // data is dropped here.
// In a real scenario, you'd construct this in-place rather than moving.
let owned = own!(init!(LargeData { buffer: init::repeat(42) }));
process_owned(owned);
For self-referential or pinned types:
use placid::{POwn, pown, InitPin, init};
use std::{pin::Pin, marker::PhantomPinned};
#[derive(InitPin)]
struct SelfRef {
data: i32,
data_ptr: *const i32,
marker: PhantomPinned,
}
fn process_pinned(data: POwn<SelfRef>) {
// The function owns the data and guarantees it won't move.
// This is safe because the data is pinned in place.
}
let pinned = pown!(
// Provide initial value for the struct.
init::value(SelfRef {
data: 42,
data_ptr: std::ptr::null(),
marker: PhantomPinned,
})
.and_pin(|this| unsafe {
// SAFETY: We are initializing the self-referential pointer.
let this = Pin::into_inner_unchecked(this);
this.data_ptr = &this.data as *const i32;
})
);
process_pinned(pinned);
Moving out an owned reference from a regular smart pointer:
use placid::{Own, into_own, Place};
let boxed = Box::new(String::from("move me"));
let mut left; // Box<MaybeUninit<String>>
// Move out an owned reference from the Box. The original
// allocation is transferred to `left`, mutably borrowed
// by `own`.
let own = into_own!(left <- boxed);
assert_eq!(*own, "move me");
// Drops the String, but not the Box allocation.
drop(own);
// Now we can reuse the Box allocation.
let right = left.write(String::from("new value"));
assert_eq!(&*right, "new value");
This project is licensed under either of:
at your option.
moveitpin-init