[−][src]Crate gsrs
GSRS or Generic Self Referencing Struct
This crate helps to create custom movable self referencing structs. And with just very little unsafe. No raw pointer magic and basically just a signle unsafe lifetime trick. Although if you want to extend your struct dynamically some more unsafe is required.
Self referencing structs are generally considered an anti-pattern in Rust, so if you can easily
go without it you should do it. But sometimes you actually need to have a self referential struct.
So here are some examples when you actually need SRS
:
- You have a structs with
Vec
of big values and aHashSet
to prevent adding duplicates to it. You also need to dynamically add values to it from time to time. Also those structs are holded in another collection. Technically you might be able to workaround with indicies, or untrivially reorganising your code, but it would require additional code and makes semantics less clear.
Does not support dependent lifetimes.(is it actully needed/possible?)
Should work on any stable rust starting from 1.31(2018 edition)
Usage
Simple example:
use gsrs::*; struct Test{field:usize} #[derive(Default)] struct TestRef<'a>(Option<&'a Test>); deref_with_lifetime!(TestRef); // create owned part let mut srs = SRS::<Test, TestRef>::new( Test{ field: 5 } ); // create self-referencing part srs.with(|user, owner|*user = TestRef(Some(owner))); // get self referencing part back let r = srs.get_ref(|user, _| user.0.unwrap()); println!("{}", r.field);
or you can do creation in one go
use gsrs::*; struct Test{field:usize} struct TestRef<'a>(&'a Test); deref_with_lifetime!(TestRef); // create owned part and self-referencing part let mut srs = SRS::<Test, TestRef>::create_with( Test{ field: 5 }, |owner|TestRef(owner) ); // get self referencing part back let r = srs.get_ref(|user, _| user.0); println!("{}", r.field);
and this won't compile because get_ref
is able to supply return value with proper lifetime:
srs.with(|user, owner|*user = TestRef(Some(owner))); let r = srs.get_ref(|user, _| user.0.unwrap()); drop(srs); println!("{}",r.field);
This also will fail because it is possible to return only static types or references to static types. It is done to prevent changing some inner reference with interior mutability.
let mut srs = SRS::<Test,TestRef<'static>>::create_with( Test{field:5}, |owner|TestRef(owner), ); // here closure returns TestRef<'a> not a reference let r = srs.with(|user,_|user); let mut ow = Box::new(Test{field:0}); let r = srs.split(&mut ow); println!("{}",r.0.field);
Macros
deref_with_lifetime | Macro to implement |
Structs
SRS | Self Referencing Struct |
Traits
DerefWithLifetime | This trait should be implemented for any struct that will contain references to data inside |