Skip to main content

miden_base_macros/
lib.rs

1//! Module for Miden SDK macros
2//!
3//! ### How to use WIT generation.
4//!
5//! 1. Add `#[component]` on you `impl MyAccountType {`.
6//! 2. Add `#[export_type]` on every defined type that is used in the public(exported) method
7//!    signature.
8//!
9//! Example:
10//! ```rust,ignore
11//!
12//! #[export_type]
13//! pub struct StructA {
14//!     pub foo: Word,
15//!     pub asset: Asset,
16//! }
17//!
18//! #[export_type]
19//! pub struct StructB {
20//!     pub bar: Felt,
21//!     pub baz: Felt,
22//! }
23//!
24//! #[component]
25//! struct MyAccount;
26//!
27//! #[component]
28//! impl MyAccount {
29//!     pub fn foo(&self, a: StructA) -> StructB {
30//!         ...
31//!     }
32//! }
33//! ```
34//!
35
36//! ### Escape hatch (disable WIT generation)
37//!
38//! in a small fraction of the cases where the WIT generation is not possible (think a type defined
39//! only in an external WIT file) or not desirable the WIT generation can be disabled:
40//!
41//! To disable WIT interface generation:
42//! - Don't use `#[component]` attribute macro in the `impl MyAccountType` section;
43//!
44//! To use manually crafted WIT interface:
45//! - Put the WIT file in the `wit` folder;
46//! - call `miden::generate!();` and `bindings::export!(MyAccountType);`
47//! - implement `impl Guest for MyAccountType`;
48
49use crate::script::ScriptConfig;
50
51extern crate proc_macro;
52
53mod account_component_metadata;
54mod boilerplate;
55mod component_macro;
56mod export_type;
57mod generate;
58mod manifest_paths;
59mod note;
60mod script;
61mod types;
62mod util;
63
64/// Generates the WIT interface and storage metadata.
65///
66/// **NOTE:** Mark each type used in the public method with `#[export_type]` attribute macro.
67///
68/// To disable WIT interface generation:
69/// - don't use `#[component]` attribute macro in the `impl MyAccountType` section;
70///
71/// To use manually crafted WIT interface:
72/// - put WIT interface file in the `wit` folder;
73/// - call `miden::generate!();` and `bindings::export!(MyAccountType);`
74/// - implement `impl Guest for MyAccountType`;
75#[proc_macro_attribute]
76pub fn component(
77    attr: proc_macro::TokenStream,
78    item: proc_macro::TokenStream,
79) -> proc_macro::TokenStream {
80    component_macro::component(attr, item)
81}
82
83/// Generates an equvalent type in the WIT interface.
84/// Required for every type mentioned in the public methods of an account component.
85///
86/// Intended to be used together with `#[component]` attribute macro.
87#[proc_macro_attribute]
88pub fn export_type(
89    attr: proc_macro::TokenStream,
90    item: proc_macro::TokenStream,
91) -> proc_macro::TokenStream {
92    export_type::expand(attr, item)
93}
94
95/// Marks a type/impl as a note script definition.
96///
97/// This attribute is intended to be used on:
98/// - a note input type definition (`struct MyNote { ... }`)
99/// - the associated inherent `impl` block that contains an entrypoint method annotated with
100///   `#[note_script]`
101///
102/// # Example
103///
104/// ```rust,ignore
105/// use miden::*;
106/// use crate::bindings::Account;
107///
108/// #[note]
109/// struct MyNote {
110///     recipient: AccountId,
111/// }
112///
113/// #[note]
114/// impl MyNote {
115///     #[note_script]
116///     pub fn run(self, _arg: Word, account: &mut Account) {
117///         assert_eq!(account.get_id(), self.recipient);
118///     }
119/// }
120/// ```
121#[proc_macro_attribute]
122pub fn note(
123    attr: proc_macro::TokenStream,
124    item: proc_macro::TokenStream,
125) -> proc_macro::TokenStream {
126    note::expand_note(attr, item)
127}
128
129/// Marks a method as the note script entrypoint (`#[note_script]`).
130///
131/// The method must be contained within an inherent `impl` block annotated with `#[note]`.
132///
133/// # Supported entrypoint signature
134///
135/// - Receiver must be plain `self` (by value); `&self`, `&mut self`, `mut self`, and typed
136///   receivers (e.g. `self: Box<Self>`) are not supported.
137/// - The method must return `()`.
138/// - Excluding `self`, the method must accept:
139///   - exactly one `Word` argument, and
140///   - optionally a single `&Account` or `&mut Account` argument (in either order).
141/// - Generic methods and `async fn` are not supported.
142#[proc_macro_attribute]
143pub fn note_script(
144    attr: proc_macro::TokenStream,
145    item: proc_macro::TokenStream,
146) -> proc_macro::TokenStream {
147    note::expand_note_script(attr, item)
148}
149
150/// Marks the function as a transaction script
151#[proc_macro_attribute]
152pub fn tx_script(
153    attr: proc_macro::TokenStream,
154    item: proc_macro::TokenStream,
155) -> proc_macro::TokenStream {
156    script::expand(
157        attr,
158        item,
159        ScriptConfig {
160            export_interface: "miden:base/transaction-script@1.0.0",
161            guest_trait_path: "self::bindings::exports::miden::base::transaction_script::Guest",
162        },
163    )
164}
165
166/// Generate bindings for an input WIT document.
167///
168/// The macro here will parse [WIT] as input and generate Rust bindings to work with the `world`
169/// that's specified in the [WIT]. For a primer on WIT see [this documentation][WIT] and for a
170/// primer on worlds see [here][worlds].
171///
172/// [WIT]: https://component-model.bytecodealliance.org/design/wit.html
173/// [worlds]: https://component-model.bytecodealliance.org/design/worlds.html
174///
175/// For documentation on each option, see below.
176///
177/// ## Exploring generated bindings
178///
179/// Once bindings have been generated they can be explored via a number of means
180/// to see what was generated:
181///
182/// * Using `cargo doc` should render all of the generated bindings in addition
183///   to the original comments in the WIT format itself.
184/// * If your IDE supports `rust-analyzer` code completion should be available
185///   to explore and see types.
186///
187/// ## Namespacing
188///
189/// The generated bindings are put in `bindings` module.
190/// In WIT, worlds can import and export `interface`s, functions, and types. Each
191/// `interface` can either be "anonymous" and only named within the context of a
192/// `world` or it can have a "package ID" associated with it. Names in Rust take
193/// into account all the names associated with a WIT `interface`. For example
194/// the package ID `foo:bar/baz` would create a `mod foo` which contains a `mod
195/// bar` which contains a `mod baz`.
196///
197/// WIT imports and exports are additionally separated into their own
198/// namespaces. Imports are generated at the level of the `generate!` macro
199/// where exports are generated under an `exports` namespace.
200///
201/// ## Exports: The `export!` macro
202///
203/// Components are created by having exported WebAssembly functions with
204/// specific names, and these functions are not created when `generate!` is
205/// invoked. Instead these functions are created afterwards once you've defined
206/// your own type an implemented the various `trait`s for it. The
207/// `#[unsafe(no_mangle)]` functions that will become the component are created
208/// with the generated `export!` macro.
209///
210/// Each call to `generate!` will itself generate a macro called `export!`.
211/// The macro's first argument is the name of a type that implements the traits
212/// generated:
213///
214/// ```rust,ignore
215/// use miden::generate;
216///
217/// generate!({
218///     inline: r#"
219///         package my:test;
220///
221///         world my-world {
222/// #           export hello: func();
223///             // ...
224///         }
225///     "#,
226/// });
227///
228/// struct MyComponent;
229///
230/// impl Guest for MyComponent {
231/// #   fn hello() {}
232///     // ...
233/// }
234///
235/// export!(MyComponent);
236/// #
237/// # fn main() {}
238/// ```
239///
240/// This argument is a Rust type which implements the `Guest` traits generated
241/// by `generate!`. Note that all `Guest` traits must be implemented for the
242/// type provided or an error will be generated.
243///
244/// ## Options to `generate!`
245///
246/// The full list of options that can be passed to the `generate!` macro are as
247/// follows. Note that there are no required options, they all have default
248/// values.
249///
250///
251/// ```rust,ignore
252/// use miden::generate;
253/// # macro_rules! generate { ($($t:tt)*) => () }
254///
255/// generate!({
256///     // Enables passing "inline WIT". If specified this is the default
257///     // package that a world is selected from. Any dependencies that this
258///     // inline WIT refers to must be defined in the `path` option above.
259///     //
260///     // By default this is not specified.
261///     inline: "
262///         world my-world {
263///             import wasi:cli/imports;
264///
265///             export my-run: func()
266///         }
267///     ",
268///
269///     // When generating bindings for interfaces that are not defined in the
270///     // same package as `world`, this option can be used to either generate
271///     // those bindings or point to already generated bindings.
272///     // For example, if your world refers to WASI types then the `wasi` crate
273///     // already has generated bindings for all WASI types and structures. In this
274///     // situation the key `with` here can be used to use those types
275///     // elsewhere rather than regenerating types.
276///     // If for example your world refers to some type and you want to use
277///     // your own custom implementation of that type then you can specify
278///     // that here as well. There is a requirement on the remapped (custom)
279///     // type to have the same internal structure and identical to what would
280///     // wit-bindgen generate (including alignment, etc.), since
281///     // lifting/lowering uses its fields directly.
282///     //
283///     // If, however, your world refers to interfaces for which you don't have
284///     // already generated bindings then you can use the special `generate` value
285///     // to have those bindings generated.
286///     //
287///     // The `with` key here works for interfaces and individual types.
288///     //
289///     // When an interface or type is specified here no bindings will be
290///     // generated at all. It's assumed bindings are fully generated
291///     // somewhere else. This is an indicator that any further references to types
292///     // defined in these interfaces should use the upstream paths specified
293///     // here instead.
294///     //
295///     // Any unused keys in this map are considered an error.
296///     with: {
297///         "wasi:io/poll": wasi::io::poll,
298///         "some:package/my-interface": generate,
299///         "some:package/my-interface/my-type": my_crate::types::MyType,
300///     },
301/// });
302/// ```
303///
304#[proc_macro]
305pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
306    generate::expand(input)
307}