12 breaking releases

0.13.0 Dec 18, 2025
0.12.0 Jan 26, 2025
0.11.0 Jan 7, 2025
0.10.1 Nov 29, 2024
0.2.0 Nov 27, 2023

#50 in #rpc-service


Used in 2 crates

MIT/Apache

590KB
16K SLoC

Aldrin macros

The macros in this crate are not generally meant to be used directly, but through re-exports in other crates.

Procedural macros

  • generate: Re-exported in crate aldrin
  • service: Re-exported in crate aldrin

Derive macros

All derive macros are re-exported in both aldrin and aldrin-core.

Attributes

All derive macros support various attributes and some apply to multiple macros.

Container attributes

crate

The attribute #[aldrin(crate = ...) can be used to override the path of the aldrin_core crate. This is useful when aldrin_core is not a direct dependency, but only reexported somewhere. The default value depends on from where the macro is invoked, it's either ::aldrin::core or ::aldrin_core.

mod my_reexports {
    pub use aldrin_core as my_aldrin_core;
}

#[derive(
    my_reexports::my_aldrin_core::Tag,
    my_reexports::my_aldrin_core::PrimaryTag,
    my_reexports::my_aldrin_core::RefType,
    my_reexports::my_aldrin_core::Serialize,
    my_reexports::my_aldrin_core::Deserialize,
)]
#[aldrin(crate = my_reexports::my_aldrin_core, ref_type)]
struct Person {
    name: String,
}
schema

Deriving Introspectable requires specifying a schema name. It is an error if this attribute is missing.

#[derive(Introspectable)]
#[aldrin(schema = "contacts")]
struct Person {
    name: String,
}
ref_type

Deriving RefType requires specifying an identifier for the type with the #[aldrin(ref_type = ...)] attribute. The Serialize and SerializeKey derive macro will then also generate implementations for that type.

It is also possible to specifiy just #[aldrin(ref_type)] without an identifer. In this case, a default will be chosen by appending Ref to the name of the annotated type.

newtype

Specifying #[aldrin(newtype)] is possible for structs with exactly 1 field and makes them behave like that field. E.g., the type will no longer serialize as a struct, but directly as that field instead.

#[derive(
    Tag,
    KeyTag,
    PrimaryTag,
    PrimaryKeyTag,
    Serialize,
    SerializeKey,
    Deserialize,
    DeserializeKey,
)]
#[aldrin(newtype)]
struct Name {
    inner: String,
}
doc

Provides an alternative doc string used only for deriving Introspectable. Note that this attribute can be used anywhere a regular doc comment can be used as well.

If this is not provided then Introspectable will fall back to the regular doc comment (if present).

Using this attribute can be desirable if the regular doc comment is Rust-specific, e.g. due to link conversion or other modifications.

/// This doc comment will be rendered by rustdoc.
#[derive(Introspectable)]
#[aldrin(schema = "family_tree")]
#[aldrin(doc = "This doc comment will be used for introspection.")]
struct Name {
    /// This doc comment will be rendered by rustdoc.
    #[aldrin(doc = "This doc comment will be used for introspection.")]
    inner: String,
}

Field and variant attributes

id

Use #[aldrin(id = ...)] to override the automatically defined id for a field or variant.

Default ids start at 0 for the first field or variant and then increment by 1 for each subsequent field or variant.

#[derive(Tag, PrimaryTag, RefType, Serialize, Deserialize, Introspectable)]
#[aldrin(schema = "family_tree", ref_type)]
struct Person {
    age: u8, // id = 0

    #[aldrin(id = 5)]
    name: String, // id = 5

    siblings: Vec<Self>, // id = 6
}
#[derive(Tag, PrimaryTag, RefType, Serialize, Deserialize, Introspectable)]
#[aldrin(schema = "pets", ref_type)]
enum Pet {
    Dog, // id = 0

    #[aldrin(id = 5)]
    Cat, // id = 5

    Alpaca, // id = 6
}
optional

Use #[aldrin(optional)] to mark fields of a struct as optional. They must be of an Option<T> type.

Optional fields are not serialized if None and are allowed to be missing when deserializing a value.

#[derive(Tag, PrimaryTag, RefType, Serialize, Deserialize, Introspectable)]
#[aldrin(schema = "example", ref_type)]
struct MyStruct {
    required_field_1: i32,
    required_field_2: Option<i32>,

    #[aldrin(optional)]
    optional_field: Option<i32>,
}

Both fields required_field_1 and required_field_2 will always be serialized and deserialization will fail if either is missing. Serialization of optional_field is skipped if it is None. If it's missing during deserialization, then it will be set to None.

fallback

The last field of a struct and the last variant of an enum can optionally be marked with #[aldrin(fallback)]. This will enable successful serialization and deserialization of unknown fields and variants. For structs, the field type must be aldrin_core::UnknownFields. For enums, the variant must have a single field of type aldrin_core::UnknownVariant.

This attribute cannot be combined with #[aldrin(optional)].

Example of a struct with a fallback field:

#[derive(Tag, PrimaryTag, RefType, Serialize, Deserialize, Introspectable)]
#[aldrin(schema = "contacts", ref_type)]
struct Person {
    name: String,
    age: u8,

    #[aldrin(fallback)]
    unknown_fields: UnknownFields,
}

Example of an enum with a fallback variant:

#[derive(Tag, PrimaryTag, RefType, Serialize, Deserialize, Introspectable)]
#[aldrin(schema = "zoo", ref_type)]
enum AnimalType {
    Alpaca,
    Pig,

    #[aldrin(fallback)]
    Unkown(UnknownVariant),
}
doc

See doc for containers.

Dependencies

~7–9.5MB
~196K SLoC