I've just published a new, vastly improved version of rental
. This crate allows you to define arbitrarily self-referential structs, and even chain such structs together transitively.
Taken from the readme, here's the classic libloading
example, where we want to store a dylib and a symbol from it in the same struct:
rental! {
pub mod rent_libloading {
use libloading;
#[rental(deref_suffix)] // This struct will deref to the target of Symbol.
pub struct RentSymbol<S: 'static> {
lib: Box<libloading::Library>, // Library is boxed for stable deref.
sym: libloading::Symbol<'lib, S>, // The 'lib lifetime borrows lib.
}
}
}
fn main() {
let lib = libloading::Library::new("my_lib.so").unwrap(); // Open our dylib.
if let Ok(rs) = rent_libloading::RentSymbol::try_new(
Box::new(lib),
|lib| unsafe { lib.get::<extern "C" fn()>(b"my_symbol") }) // Loading Symbols is unsafe.
{
(*rs)(); // Call our function
};
}
Here, instead of the old 'rental
lifetime, that nonsense is gone and each field has a lifetime named after it. This allows for far more flexible arrangements. This example was simple, but let's take a look at one for alto
which was impossible in the previous version:
rental! {
pub mod rent_alto {
use alto;
#[rental]
pub struct RentContext {
alto: Box<alto::Alto>,
dev: Box<alto::Device<'alto>>,
ctx: alto::Context<'dev>,
}
}
}
fn main() {
let alto = alto::Alto::load_default().unwrap(); // Load the default OpenAL impl.
if let Ok(rent_ctx) = rent_alto::RentContext::try_new(
Box::new(alto),
|alto| alto.open(None).map(|dev| Box::new(dev)), // Open the default device.
|dev, _alto| dev.new_context(None), // Create a new context for our device.
) {
rent_ctx.rent(|ctx| {
// Do stuff with our context
});
};
}
The old version didn't support 3 or more layers of self-reference. It always chafed that I was the author of two crates that couldn't even be used together, so I'm glad to finally have this resolved. You can go as many levels deep as you want (well, up to 32 right now, but I can easily raise the limit if necessary). Here's a more contrived example from the test suite:
rental! {
mod rentals {
use super::*;
#[rental]
pub struct ComplexRent {
foo: Box<Foo>,
bar: Box<Bar<'foo>>,
baz: Box<Baz<'foo, 'bar>>,
qux: Box<Qux<'foo, 'bar, 'baz>>,
xyzzy: Xyzzy<'foo, 'bar, 'baz, 'qux>,
}
}
}
There are still some limitations as described in the readme, but this version is far, far more capable than the old one was. After taking a break for a little while I'll update alto to use it.
Let me know if you have any questions or suggestions or what have you. I'm eager to start putting this to use.