Macro self_cell::self_cell [−][src]
macro_rules! self_cell { ( $(#[$StructMeta:meta])* $Vis:vis struct $StructName:ident { #[$ConstructorType:ident] owner: $Owner:ty, #[$Covariance:ident] dependent: $Dependent:ident, } $(impl {$($AutomaticDerive:ident),*})? ) => { ... }; }
This macro declares a new struct of $StructName
and implements traits
based on $AutomaticDerive
.
Example:
use self_cell::self_cell; #[derive(Debug, Eq, PartialEq)] struct Ast<'a>(pub Vec<&'a str>); impl<'a> From<&'a String> for Ast<'a> { fn from(body: &'a String) -> Self { Ast(vec![&body[2..5], &body[1..3]]) } } self_cell!( #[doc(hidden)] struct PackedAstCell { #[from] owner: String, #[covariant] dependent: Ast, } impl {Clone, Debug, PartialEq, Eq, Hash} );
See the crate overview to get a get an overview and a motivating example.
Parameters:
-
$Vis:vis struct $StructName:ident
Name of the struct that will be declared, this needs to be unique for the relevant scope. Example:struct AstCell
orpub struct AstCell
.$(#[$StructMeta:meta])*
allows you specify further meta items for this struct, eg.#[doc(hidden)] struct AstCell
. -
$ConstructorType:ident
Marker declaring if a regular::new
or::try_from
constructor should be generated. Possible Values:-
from: This generates a
fn new(owner: $Owner) -> Self
constructor. For this to work<&'a $Owner>::Into<$Dependent<'a>>
has to be implemented. -
try_from: This generates a
fn try_from<'a>(owner: $Owner) -> Result<Self, <&'a $Owner as TryInto<$Dependent<'a>>>::Error>
constructor, which allows fallible construction without having to check for failure every time dependent is accessed. For this to work<&'a $Owner>::TryInto<$Dependent<'a>>
has to be implemented. -
from_fn: This generates a
fn from_fn(owner: $Owner, dependent_builder: impl for<'a> FnOnce(&'a $Owner) -> $Dependent<'a>) -> Self
constructor, which allows more flexible construction that can also return additional unrelated state. But has the drawback of preventing Clone from being automatically implemented. A Fn or FnMut would have to be stored to enable this. However you can still implement Clone yourself.
NOTE: If
<&'a $Owner>::Into<$Dependent<'a>>
panics, the value of owner and a heap struct will be leaked. This is safe, but might not be what you want. See How to avoid leaking memory ifDependen::from(&Owner)
panics. -
-
$Owner:ty
Type of owner. This has to have a'static
lifetime. Example:String
. -
$Dependent:ident
Name of the dependent type without specified lifetime. This can’t be a nested type name. As workaround either create a type aliastype Dep<'a> = Option<Vec<&'a str>>;
or create a new-typestruct Dep<'a>(Option<Vec<&'a str>>);
. Example:Ast
.$Covariance:ident
Marker declaring if$Dependent
is covariant. Possible Values:-
covariant: This generates the direct reference accessor function
fn borrow_dependent<'a>(&'a self) -> &'a $Dependent<'a>
. This is only safe to do if this compilesfn _assert_covariance<'x: 'y, 'y>(x: $Dependent<'x>) -> $Dependent<'y> { x }
. Otherwise you could choose a lifetime that is too short for types with interior mutability likeCell
, which can lead to UB in safe code. Which would violate the promise of this library that it is safe-to-use. If you accidentally mark a type that is not covariant as covariant, you will get a compile time error. -
not_covariant: This generates no additional code but you can use
fn with_dependent<Ret>(&self, func: impl for<'a> FnOnce(&'a $Owner, &'a $Dependent<'a>) -> Ret) -> Ret
. See How to build a lazy AST with self_cell for a usage example.
-
-
impl {$($AutomaticDerive:ident),*},
Optional comma separated list of optional automatic trait implementations. Possible Values:-
Clone: Logic
cloned_owner = owner.clone()
and then callscloned_owner.into()
to create cloned SelfCell. -
Debug: Prints the debug representation of owner and dependent. Example:
AstCell { owner: "fox = cat + dog", dependent: Ast(["fox", "cat", "dog"]) }
-
PartialEq: Logic
*self.borrow_owner() == *other.borrow_owner()
, this assumes thatDependent<'a>::From<&'a Owner>
is deterministic, so that only comparing owner is enough. -
Eq: Will implement the trait marker
Eq
for$StructName
. Beware if you select thisEq
will be implemented regardless if$Owner
implementsEq
, that’s an unfortunate technical limitation. -
Hash: Logic
self.borrow_owner().hash(state);
, this assumes thatDependent<'a>::From<&'a Owner>
is deterministic, so that only hashing owner is enough.
All
AutomaticDerive
are optional and you can implement you own version of these traits. The declared struct is part of your module and you are free to implement any trait in any way you want. Access to the unsafe internals is only possible via unsafe functions, so you can’t accidentally use them in safe code. -