Macro self_cell::self_cell

source ·
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 or pub 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 alias type Dep<'a> = Option<Vec<&'a str>>; or create a new-type struct 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 compiles fn _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 like Cell, 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 that Dependent<'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 this Eq will be implemented regardless if $Owner implements Eq, that’s an unfortunate technical limitation.

    • Hash: Logic self.borrow_owner().hash(state);, this assumes that Dependent<'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, no AutomaticDerive are supported if an owner lifetime is provided.