Macro aldrin::generate

source ·
generate!() { /* proc-macro */ }
Expand description

Generates code from an Aldrin schema.

§Basic usage

The generate! macro takes one required argument, the path to the schema file. Paths can be relative to Cargo.toml file. This requires building with Cargo (or more specifically, the CARGO_MANIFEST_DIR environment variable). Building without Cargo currently supports only absolute paths.

The generated code depends only the aldrin-client crate. Make sure you have it specified as a dependency in your Cargo.toml.

generate!("schemas/example1.aldrin");

fn main() {
    example1::MyStruct::builder()
        .field1(12)
        .field2(34)
        .build();
}

This generates the module example1 with the same content as if the stand-alone code generator was used.

The module has pub visibility, which is not always desired, especially in library crates. A common pattern is to put the generated modules inside an additional schemas module:

mod schemas {
    generate!("schemas/example1.aldrin");
}

If you have only a single schema, it is occasionally convenient to put the generated code inside another module (like above), but then also re-export everything into it:

mod schema {
    generate!("schemas/example1.aldrin");
    pub use example1::*;
}

fn main() {
    schema::MyStruct::builder() // Note `schema` instead of `example1`.
        .field1(12)
        .field2(34)
        .build();
}

§Multiple schemas

It is possible to pass additional paths to the macro. Code will then be generated for all of them:

generate! {
    "schemas/example1.aldrin",
    "schemas/example2.aldrin",
}

Any additional options (see below) will be applied to all schemas. If this is not desired, then the macro can be called multiple times instead.

§Include directories

You can specify include directories with include = "path":

generate! {
    "schemas/example3.aldrin",
    "schemas/example4.aldrin",
    include = "schemas",
}

fn main() {
    example3::Foo::builder()
        .bar(example4::Bar::builder().baz(12).build())
        .build();
}

The include option can be repeated multiple times.

§Skipping server or client code

You can skip generating server or client code for services by setting server = false or client = false. This will only affect services and types defined inside (inline structs and enums), but not other top-level definitions.

Both settings default to true.

§Patching the generated code

You can specify additional patch files, which will be applied to the generated code. This allows for arbitrary changes, such as for example custom additional derives.

Patches can only be specified when generating code for a single schema.

generate! {
    "schemas/example1.aldrin",
    patch = "schemas/example1-rename.patch",
}

fn main() {
    example1::MyStructRenamed::builder()
        .field1(12)
        .field2(34)
        .build();
}

Patches are applied in the order they are specified.

generate! {
    "schemas/example1.aldrin",
    patch = "schemas/example1-rename.patch",
    patch = "schemas/example1-rename-again.patch",
}

fn main() {
    example1::MyStructRenamedAgain::builder()
        .field1(12)
        .field2(34)
        .build();
}

§Omitting struct builders

For every struct in the schema, usually a corresponding builder is generated as well. This can be turned off by setting struct_builders = false.

generate! {
    "schemas/example1.aldrin",
    struct_builders = false,
}

fn main() {
    // example1::MyStruct::builder() and example1::MyStructBuilder are not generated

    let my_struct = example1::MyStruct {
        field1: Some(42),
        field2: None,
    };
}

§Omitting #[non_exhaustive] attribute

The #[non_exhaustive] attribute can optionally be skipped on structs, enums, service event enums and service function enums. Set one or more of:

  • struct_non_exhaustive = false
  • enum_non_exhaustive = false
  • event_non_exhaustive = false
  • function_non_exhaustive = false
generate! {
    "schemas/example1.aldrin",
    struct_non_exhaustive = false,
    enum_non_exhaustive = false,
    event_non_exhaustive = false,
    function_non_exhaustive = false,
}

§Errors and warnings

Any errors and warnings from the schemas will be shown as part of the regular compiler output. No code will be generated, if there are any errors in the schemas.

Warnings can currently only be emitted on nightly Rust. They are silently ignored on stable and beta. Unfortunately, this may suppress important diagnostics about your schemas. You can use the option warnings_as_errors = true to treat all warnings as errors.

On the other hand, if you are on nightly Rust and generate code for a foreign schema, which you have no direct influence on, warnings may clutter your compiler output. In that case you can use suppress_warnings = true to ignore all warnings.

In general, it is advisable to use warnings_as_errors for your own schemas, and suppress_warnings for foreign schemas:

// Own schema
generate! {
    "schemas/example5.aldrin",
    include = "schemas/foreign",
    warnings_as_errors = true,
}

// Foreign schema
generate! {
    "schemas/foreign/example6.aldrin",
    suppress_warnings = true,
}