Skip to content

Repository files navigation

Pair

GitHubcrates.iodocs.rsLicense

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)]pubstructMyBuffer{data:String,}// And you have some borrowing "parsed" representation, containing string slices#[derive(Debug)]pubstructParsed<'a>{tokens:Vec<&'astr>,}// And you have some expensive parsing function you only want to run oncefnparse(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>forMyBuffer{typeDependent = Parsed<'owner>;}// Define how to make a Parsed<'_> from a &MyBufferimplOwnerforMyBuffer{typeContext<'a> = ();// We don't need any extra args to `make_dependent`typeError = std::convert::Infallible;// Our example parsing can't failfnmake_dependent(&self, _:()) -> Result<Dependent<'_,Self>,Self::Error>{Ok(parse(self))}}// You can now use MyBuffer in a Pair:fnmain(){// A Pair can be constructed from an owner value (MyBuffer, in this example)letmut pair = Pair::new(MyBuffer{data:String::from("this is an example"),});// You can obtain a reference to the owner via a reference to the pairlet 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.

Related Projects

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.

About

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

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages