Crate pair

Source
Expand description

§Pair

GitHub crates.io docs.rs License

Safe API for generic self-referential pairs of owner and dependent.

You define how to construct a dependent type from a reference to an owning type, and Pair will carefully bundle them together in a safe and freely movable self-referential struct.

§Example Usage

A typical use case might look something like this:

use pair::{Dependent, HasDependent, Owner, Pair};

// Let's say you have some buffer type that contains a string
#[derive(Debug)]
pub struct MyBuffer {
    data: String,
}

// And you have some borrowing "parsed" representation, containing string slices
#[derive(Debug)]
pub struct Parsed<'a> {
    tokens: Vec<&'a str>,
}

// And you have some expensive parsing function you only want to run once
fn parse(buffer: &MyBuffer) -> Parsed<'_> {
    let tokens = buffer.data.split_whitespace().collect();
    Parsed { tokens }
}



// You would then implement HasDependent and Owner for MyBuffer:

// Defines the owner/dependent relationship between MyBuffer and Parsed<'_>
impl<'owner> HasDependent<'owner> for MyBuffer {
    type Dependent = Parsed<'owner>;
}

// Define how to make a Parsed<'_> from a &MyBuffer
impl Owner for MyBuffer {
    type Context<'a> = (); // We don't need any extra args to `make_dependent`
    type Error = std::convert::Infallible; // Our example parsing can't fail

    fn make_dependent(&self, _: ()) -> Result<Dependent<'_, Self>, Self::Error> {
        Ok(parse(self))
    }
}



// You can now use MyBuffer in a Pair:
fn main() {
    // A Pair can be constructed from an owner value (MyBuffer, in this example)
    let mut pair = Pair::new(MyBuffer {
        data: String::from("this is an example"),
    });

    // You can obtain a reference to the owner via a reference to the pair
    let owner: &MyBuffer = pair.owner();
    assert_eq!(owner.data, "this is an example");

    // You can access a reference to the dependent via a reference to the pair,
    // but only within a provided closure.
    // See the documentation of `Pair::with_dependent` for details.
    let kebab = pair.with_dependent(|parsed: &Parsed<'_>| parsed.tokens.join("-"));
    assert_eq!(kebab, "this-is-an-example");

    // However, if the dependent is covariant over its lifetime (as our example
    // Parsed<'_> is) you can trivially extract the dependent from the closure.
    // This will not compile if the dependent is not covariant.
    let parsed: &Parsed<'_> = pair.with_dependent(|parsed| parsed);
    assert_eq!(parsed.tokens, ["this", "is", "an", "example"]);

    // You can obtain a mutable reference to the dependent via a mutable
    // reference to the pair, but only within a provided closure.
    // See the documentation of `Pair::with_dependent_mut` for details.
    pair.with_dependent_mut(|parsed| parsed.tokens.pop());
    assert_eq!(pair.with_dependent(|parsed| parsed.tokens.len()), 3);

    // If you're done with the dependent, you can recover the owner.
    // This will drop the dependent.
    let my_buffer: MyBuffer = pair.into_owner();
}

§How it Works

Note: the implementation details described in this section are not part of the crate’s public API, and are subject to change.

Under the hood, Pair moves the owner onto the heap, giving it a stable memory address. It is then borrowed and used to construct the dependent, which is also moved onto the heap. The dependent is type-erased, so that its inexpressible self-referential lifetime goes away. All exposed APIs are careful to ensure type and aliasing rules are upheld, regardless of anything safe user code could do. When the owner needs to be dropped or recovered, the dependent will first be recovered and dropped, ending the borrow of the owner. At that point, the owner can safely be recovered and the Pair deconstructed.

CrateMacro freeNo allocMaintainedSoundness
pairNo known issues
ouroboros⚠️ Unsound ⚠️
self_cellNo known issues
yoke⚠️ Unsound ⚠️
selfie⚠️ Unsound ⚠️
nolifeNo known issues
owning_ref⚠️ Unsound ⚠️
rental⚠️ Unsound ⚠️
fortifyNo known issues
loanedNo known issues
selfrefNo known issues
self-reference⚠️ Unsound ⚠️
zcNo known issues

§License

Licensed under either of:

at your option.

§Contribution

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.

Structs§

Pair
A self-referential pair containing both some Owner and its Dependent.

Traits§

HasDependent
Defines the dependent type for the Owner trait.
Owner
A type which can act as the “owner” of some data, and can produce some dependent type which borrows from Self. Used for the Pair struct.

Type Aliases§

Dependent
A type alias for the Dependent of some Owner with a specific lifetime 'owner.