macro_rules! self_cell { ( $(#[$StructMeta:meta])* $Vis:vis struct $StructName:ident $(<$OwnerLifetime:lifetime>)? { owner: $Owner:ty, #[$Covariance:ident] dependent: $Dependent:ident, } $(impl {$($AutomaticDerive:ident),*})? ) => { ... }; }
Expand description
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>(Vec<&'a str>);
self_cell!(
#[doc(hidden)]
struct PackedAstCell {
owner: String,
#[covariant]
dependent: Ast,
}
impl {Debug, PartialEq, Eq, Hash}
);
See the crate overview to get a get an overview and a motivating example.
§Generated API:
The macro implements these constructors:
fn new(
owner: $Owner,
dependent_builder: impl for<'a> ::core::ops::FnOnce(&'a $Owner) -> $Dependent<'a>
) -> Self
fn try_new<Err>(
owner: $Owner,
dependent_builder: impl for<'a> ::core::ops::FnOnce(&'a $Owner) -> Result<$Dependent<'a>, Err>
) -> Result<Self, Err>
fn try_new_or_recover<Err>(
owner: $Owner,
dependent_builder: impl for<'a> ::core::ops::FnOnce(&'a $Owner) -> Result<$Dependent<'a>, Err>
) -> Result<Self, ($Owner, Err)>
The macro implements these methods:
fn borrow_owner<'a>(&'a self) -> &'a $Owner
// Only available if dependent is covariant.
fn borrow_dependent<'a>(&'a self) -> &'a $Dependent<'a>
fn with_dependent<'outer_fn, Ret>(
&'outer_fn self,
func: impl for<'a> ::core::ops::FnOnce(&'a $Owner, &'outer_fn $Dependent<'a>
) -> Ret) -> Ret
fn with_dependent_mut<'outer_fn, Ret>(
&'outer_fn mut self,
func: impl for<'a> ::core::ops::FnOnce(&'a $Owner, &'outer_fn mut $Dependent<'a>) -> Ret
) -> Ret
fn into_owner(self) -> $Owner
§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
.$Vis
can be used to mark the struct and all functions implemented by the macro as public.$(#[$StructMeta:meta])*
allows you specify further meta items for this struct, eg.#[doc(hidden)] struct AstCell
. -
$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
borrow_dependent
. This is only safe to do if this compilesfn _assert_covariance<'x: 'y, 'y>(x: &'y $Dependent<'x>) -> &'y $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 the
with_dependent
function. See How to build a lazy AST with self_cell for a usage example.
In both cases you can use the
with_dependent_mut
function to mutate the dependent value. This is safe to do because notionally you are replacing pointers to a value not the other way around. -
-
impl {$($AutomaticDerive:ident),*},
Optional comma separated list of optional automatic trait implementations. Possible Values:-
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.There is limited nested cell support. Eg, having an owner with non static references. Eg
struct ChildCell<'a> { owner: &'a String, ...
. You can use any lifetime name you want, except_q
and only a single lifetime is supported, and can only be used in the owner. Due to macro_rules limitations, noAutomaticDerive
are supported if an owner lifetime is provided. -