placid

Crates.ioplacid
lib.rsplacid
version0.1.0
created_at2026-01-11 10:40:02.521202+00
updated_at2026-01-11 10:40:02.521202+00
descriptionSeparated ownership and in-place construction in Rust
homepage
repositoryhttps://github.com/js2xxx/placid
max_upload_size
id2035528
size209,570
Js2xxx (js2xxx)

documentation

https://docs.rs/placid

README

placid - Separated ownership and in-place construction

Cargo Documentation License

placid 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.

The problem

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:

  • You need to construct large values in-place to build address-aware objects ergonomically;
  • You want to transfer ownership of large objects without expensive 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.

Features

  • 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.

Usage

Add placid to your Cargo.toml:

[dependencies]
placid = "<the current version>"

Basic Ownership

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);

Pinned Types

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 Ownership

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");

License

This project is licensed under either of:

at your option.

References

Commit count: 48

cargo fmt