Metaprogramming
std::meta is the entry point for Noir's metaprogramming API. This consists of comptime functions
and types used for inspecting and modifying Noir programs.
Functions
type_of
pub comptime fn type_of<T>(x: T) -> Type {}
Returns the type of a variable at compile-time.
Example:
comptime {
    let x: i32 = 1;
    let x_type: Type = std::meta::type_of(x);
    assert_eq(x_type, quote { i32 }.as_type());
}
unquote
pub comptime fn unquote(code: Quoted) -> Quoted {
Unquotes the passed-in token stream where this function was called.
Example:
comptime {
    let code = quote { 1 + 2 };
    // let x = 1 + 2;
    let x = unquote!(code);
}
derive
#[varargs]
pub comptime fn derive(s: TypeDefinition, traits: [TraitDefinition]) -> Quoted {
Attribute placed on type definitions.
Creates a trait impl for each trait passed in as an argument.
To do this, the trait must have a derive handler registered
with derive_via beforehand. The traits in the stdlib that
can be derived this way are Eq, Ord, Default, and Hash.
Example:
#[derive(Eq, Default)]
struct Foo<T> {
    x: i32,
    y: T,
}
fn main() {
    let foo1 = Foo::default();
    let foo2 = Foo { x: 0, y: &[0] };
    assert_eq(foo1, foo2);
}
derive_via
pub comptime fn derive_via(t: TraitDefinition, f: DeriveFunction) {
Attribute placed on trait definitions.
Registers a function to create impls for the given trait
when the trait is used in a derive call. Users may use
this to register their own functions to enable their traits
to be derived by derive.
Because this function requires a function as an argument which
should produce a trait impl for any given type definition, users may find
it helpful to use a function like std::meta::make_trait_impl to
help creating these impls.
Example:
#[derive_via(derive_do_nothing)]
trait DoNothing {
    fn do_nothing(self);
}
comptime fn derive_do_nothing(s: TypeDefinition) -> Quoted {
    let typ = s.as_type();
    quote {
        impl DoNothing for $typ {
            fn do_nothing(self) {
                println("Nothing");
            }
        }
    }
}
As another example, derive_eq in the stdlib is used to derive the Eq
trait for any type definition. It makes use of make_trait_impl to do this:
comptime fn derive_eq(s: TypeDefinition) -> Quoted {
    let signature = quote { fn eq(_self: Self, _other: Self) -> bool };
    let for_each_field = |name| quote { (_self.$name == _other.$name) };
    let body = |fields| {
        if s.fields_as_written().len() == 0 {
            quote { true }
        } else {
            fields
        }
    };
    crate::meta::make_trait_impl(
        s,
        quote { $crate::cmp::Eq },
        signature,
        for_each_field,
        quote { & },
        body,
    )
}
make_trait_impl
pub comptime fn make_trait_impl<Env1, Env2>(
    s: TypeDefinition,
    trait_name: Quoted,
    function_signature: Quoted,
    for_each_field: fn[Env1](Quoted) -> Quoted,
    join_fields_with: Quoted,
    body: fn[Env2](Quoted) -> Quoted,
) -> Quoted {
A helper function to more easily create trait impls while deriving traits.
Note that this function only works for traits which:
- Have only one method
- Have no generics on the trait itself.
- E.g. Using this on a trait such as trait Foo<T> { ... }will result in the generated impl incorrectly missing theTgeneric.
If your trait fits these criteria then make_trait_impl is likely the easiest
way to write your derive handler. The arguments are as follows:
- s: The type definition to make the impl for
- trait_name: The name of the trait to derive. E.g.- quote { Eq }.
- function_signature: The signature of the trait method to derive. E.g.- fn eq(self, other: Self) -> bool.
- for_each_field: An operation to be performed on each field. E.g.- |name| quote { (self.$name == other.$name) }.
- join_fields_with: A separator to join each result of- for_each_fieldwith. E.g.- quote { & }. You can also use an empty- quote {}for no separator.
- body: The result of the field operations is passed into this function for any final processing. This is the place to insert any setup/teardown code the trait requires. If the trait doesn't require any such code, you can return the body as-is:- |body| body.
Example deriving Hash:
comptime fn derive_hash(s: TypeDefinition) -> Quoted {
    let name = quote { $crate::hash::Hash };
    let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };
    let for_each_field = |name| quote { _self.$name.hash(_state); };
    crate::meta::make_trait_impl(
        s,
        name,
        signature,
        for_each_field,
        quote {},
        |fields| fields,
    )
}
Example deriving Ord:
comptime fn derive_ord(s: TypeDefinition) -> Quoted {
    let name = quote { $crate::cmp::Ord };
    let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };
    let for_each_field = |name| quote {
        if result == $crate::cmp::Ordering::equal() {
            result = _self.$name.cmp(_other.$name);
        }
    };
    let body = |fields| quote {
        let mut result = $crate::cmp::Ordering::equal();
        $fields
        result
    };
    crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)
}