[][src]Crate gsrs

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:

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