[][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 a HashSet 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:

This example deliberately fails to compile
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.

This example deliberately fails to compile
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 DerefWithLifetime

Structs

SRS

Self Referencing Struct

Traits

DerefWithLifetime

This trait should be implemented for any struct that will contain references to data inside SRS and it should be implemented for any lifetime. Basically it just allows to apply custom lifetime to struct