macro_rules! self_cell {
(
$(#[$StructMeta:meta])*
$Vis:vis struct $StructName:ident $(<$OwnerLifetime:lifetime>)? {
owner: $Owner:ty,
#[$Covariance:ident $(, $AsyncBuilder: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>
) -> Selffn 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) -> Retfn 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
) -> Retfn into_owner(self) -> $Owner§Parameters:
-
$Vis:vis struct $StructName:identName of the struct that will be declared, this needs to be unique for the relevant scope. Example:struct AstCellorpub struct AstCell.$Viscan 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:tyType of owner. This has to have a'staticlifetime. Example:String. -
$Dependent:identName 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:identMarker declaring if$Dependentis 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_dependentfunction. See How to build a lazy AST with self_cell for a usage example.
In both cases you can use the
with_dependent_mutfunction to mutate the dependent value. This is safe to do because notionally you are replacing pointers to a value not the other way around.#[$Covariance:ident, async_builder]Optional marker that tells the macro to generateasyncconstruction functions.new,try_newandtry_new_or_recoverwill all beasyncfunctions takingasyncclosures asdependent_builderfunctions. -
-
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
Eqfor$StructName. Beware if you select thisEqwill be implemented regardless if$OwnerimplementsEq, 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
AutomaticDeriveare 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_qand only a single lifetime is supported, and can only be used in the owner. Due to macro_rules limitations, noAutomaticDeriveare supported if an owner lifetime is provided. -