2 releases
0.1.4 | Mar 1, 2020 |
---|---|
0.1.3 | Feb 28, 2020 |
0.1.2 |
|
0.1.1 |
|
0.1.0 |
|
#2148 in Data structures
19KB
172 lines
GSRS or Generic Self Referencing Struct
Allows to create almost arbitrary self referencing struct
See documentation on docs.rs for more details
Licence
MIT
lib.rs
:
GSRS or Generic Self Referencing Struct
This crate helps to create custom movable self referencing structs. Nothing magical. It just wraps Owner and references to it in single package with simple but unsafe lifetime tricks.
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
:
- If you have structure that is built on references (graph with Arena, or any structure built with slices on top of the string) and you want to be able move it to another thread, or put it into Vec.
- If your api would be much better if you will be able to return self contained values.
Does not support dependent lifetimes (yet?, 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. Although you anyway have to specify type of the referencing part because type inference is getting confused by changed lifetime. This can be fixed, but only when GATs will be stabilized.
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::<_, 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);
Referencing part can be arbitrary complex:
use gsrs::*;
struct TestRef<'a>(Vec<&'a str>);
deref_with_lifetime!(TestRef);
// create owned part and self-referencing part
let mut srs = SRS::<_, TestRef>::create_with(
"long unicode string".to_owned(),
|owner|TestRef(owner.split(' ').collect())
);
// get self referencing part back
let r = srs.get_ref(|user, _| user.0[1]);
assert_eq!("unicode", r);
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);