<p align="center"><img width="64px" title="The nolife logo is a Rust lifetime crossed with a red cross" src="https://raw.githubusercontent.com/dureuill/nolife/main/assets/nolife-tr.png"/></p>
Open a scope and then freeze it in time for future access.
[](#License)
[](https://crates.io/crates/nolife)
[](https://docs.rs/nolife)
[](https://deps.rs/repo/github/dureuill/nolife)
[](https://github.com/dureuill/nolife/actions/workflows/rust.yml)
This crate allows constructing structs that contain references and keeping them alive alongside the data they reference,
without a lifetime.
This is especially useful for zero-copy parsers that construct elaborate (and possibly costly) representations that borrow
the source data.
This crate achieves that by leveraging `async` functions. At their core, `async` functions are self-referential structs. this crate simply provides a way to ex-filtrate references outside of the async function, in a controlled manner.
# Using this crate
After you identified the data and its borrowed representation that you'd like to access without a lifetime, using this crate will typically encompass a few steps:
```rust
// Given the following types:
struct MyData(Vec<u8>);
struct MyParsedData<'a>(&'a mut MyData, /* ... */);
// 1. Define a helper type that will express where the lifetimes of the borrowed representation live.
struct MyParsedDataFamily; // empty type, no lifetime.
impl<'a> nolife::Family<'a> for MyParsedDataFamily {
type Family = MyParsedData<'a>; // Indicates how the type is tied to the trait's lifetime.
// you generally want to replace all lifetimes in the struct with the one of the trait.
}
// 2. Define a function that setups the data and its borrowed representation:
fn my_scope(
data_source: Vec<u8>, // 👈 all parameters that allow to build a `MyData`
) -> impl nolife::TopScope<Family = MyParsedDataFamily> // 👈 use the helper type we declared
{
nolife::scope!({
let mut data = MyData(data_source);
let mut parsed_data = MyParsedData(&mut data); // imagine that this step is costly...
freeze_forever!(&mut parsed_data) // gives access to the parsed data to the outside.
/* 👆 reference to the borrowed data */
})
}
// 3. Open a `BoxScope` using the previously written async function:
let mut scope = nolife::BoxScope::<MyParsedDataFamily>::new_dyn(my_scope(vec![0, 1, 2]));
// 4. Store the `BoxScope` anywhere you want
struct ContainsScope {
scope: nolife::BoxScope<MyParsedDataFamily>,
/* other data */
}
// 5. Lastly, enter the scope to retrieve access to the referenced value.