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 or pub 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 if Dependen::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 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 fn borrow_dependent<'a>(&'a self) -> &'a $Dependent<'a>. This is only safe to do if this compiles fn _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 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 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 calls cloned_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 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.