oasis_runtime_sdk_macros/
lib.rs

1#![feature(proc_macro_diagnostic)]
2#![deny(rust_2018_idioms)]
3
4use proc_macro::TokenStream;
5
6mod error_derive;
7mod event_derive;
8mod evm_derive;
9mod generators;
10mod module_derive;
11#[cfg(test)]
12mod test_utils;
13mod version_from_cargo;
14
15/// Emits a compile-time error `msg` from a macro, and uses the span of the
16/// macro invocation if possible. If span info is not available (should only
17/// happen in unit tests), panics with `msg`.
18fn emit_compile_error<S: Into<String> + Clone + std::panic::RefUnwindSafe>(msg: S) -> ! {
19    std::panic::catch_unwind(|| {
20        proc_macro2::Span::call_site()
21            .unwrap()
22            .error(msg.clone().into())
23            .emit();
24    })
25    .ok()
26    .or_else(|| {
27        panic!("{}", msg.into());
28    });
29    unreachable!(); // error().emit() already halts compilation, but type checker doesn't know that
30}
31
32/// Derives the `Event` trait on an enum.
33#[proc_macro_derive(Event, attributes(sdk_event))]
34pub fn event_derive(input: TokenStream) -> TokenStream {
35    let input = syn::parse_macro_input!(input as syn::DeriveInput);
36    event_derive::derive_event(input).into()
37}
38
39/// Derives the `Error` trait on an enum.
40// The helper attribute is `sdk_error` to avoid conflict with `thiserror::Error`.
41#[proc_macro_derive(Error, attributes(sdk_error, source, from))]
42pub fn error_derive(input: TokenStream) -> TokenStream {
43    let input = syn::parse_macro_input!(input as syn::DeriveInput);
44    error_derive::derive_error(input).into()
45}
46
47/// Derives the `EvmEvent` trait on a struct.
48#[proc_macro_derive(EvmEvent, attributes(evm_event))]
49pub fn evm_event_derive(input: TokenStream) -> TokenStream {
50    let input = syn::parse_macro_input!(input as syn::DeriveInput);
51    evm_derive::derive_evm_event(input).into()
52}
53
54/// Derives the `EvmError` trait on an enum.
55#[proc_macro_derive(EvmError, attributes(evm_error))]
56pub fn evm_error_derive(input: TokenStream) -> TokenStream {
57    let input = syn::parse_macro_input!(input as syn::DeriveInput);
58    evm_derive::derive_evm_error(input).into()
59}
60
61/// Derives traits from a non-trait `impl` block (rather than from a `struct`).
62///
63/// Only the `Module` and `EvmContract` traits are supported. In other words,
64/// given an `impl MyModule` block, the macro derives implementations needed either
65/// for implementing a module (see also the `#[handler]` and `#[migration]` attributes)
66/// or for implementing an EVM contract (see also the `#[evm_method]` attribute).
67#[proc_macro_attribute]
68pub fn sdk_derive(args: TokenStream, input: TokenStream) -> TokenStream {
69    let input = syn::parse_macro_input!(input as syn::ItemImpl);
70    match args.to_string().as_str() {
71        "Module" => module_derive::derive_module(input).into(),
72        "EvmContract" => evm_derive::derive_evm_contract(input).into(),
73        _ => emit_compile_error(
74            "#[sdk_derive] only supports #[sdk_derive(Module)] and #[sdk_derive(EvmContract)]",
75        ),
76    }
77}
78
79/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anyting on its own;
80/// it only marks functions that represent a paratime method handler.
81/// The permitted forms are:
82///  - `#[handler(call = "my_module.MyCall")]`: Marks a function that handles
83///    the "my_module.MyCall" call and can be passed to
84///    oasis_runtime_sdk::module::dispatch_call.
85///
86///  - `#[handler(prefetch = "my_module.MyCall")]`: Marks a function that handles
87///    the request to prefetch any data ahead of the "my_module.MyCall" call.
88///    Its signature should be `Fn(
89///      add_prefix: &mut dyn FnMut(Prefix) -> (),
90///      body: cbor::Value,
91///      auth_info: &AuthInfo,
92///    ) -> Result<(), oasis_runtime_sdk::error::RuntimeError>`
93///
94///  - `#[handler(query = "my_module.MyQuery")]`: Marks a function that handles
95///    the "my_module.MyQuery" query and can be passed to
96///    oasis_runtime_sdk::module::dispatch_query.
97///
98///  - `#[handler(message_result = "my_module.MyMR")]`: Marks a function that handles
99///    the "my_module.MyMR" message result and can be passed to
100///    oasis_runtime_sdk::module::dispatch_message_result.
101///
102/// Query handler can also contain the `expensive` tag. Example:
103/// `#[handler(query = "my_module.MyQuery", expensive)]`.
104/// Queries tagged `expensive` can be enabled/disabled are disabled by default to avoid
105/// excessive costs to the node operator. This can be overridden in the node config.
106///
107/// NOTE: This attribute is parsed by the `#[sdk_derive(...)]` macro, which cannot
108/// interpret the attribute name semantically. Use `#[handler]`, not
109/// `#[oasis_runtime_sdk_macros::handler]` or other paths/aliases.
110#[proc_macro_attribute]
111pub fn handler(_args: TokenStream, input: TokenStream) -> TokenStream {
112    input
113}
114
115/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
116/// it only marks functions that represent a module state migration.
117///
118/// The permitted forms are:
119///  - `#[migration(init)]`: Marks the initial (genesis) migration.
120///  - `#[migration(from = v)]`: Marks a migration from version v to v+1, where v is
121///    a non-negative integer.
122#[proc_macro_attribute]
123pub fn migration(_args: TokenStream, input: TokenStream) -> TokenStream {
124    input
125}
126
127/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
128/// it only marks functions that represent contract methods.
129///
130/// The permitted forms are:
131///  - `#[evm_method(signature = "...")]`: The method selector is computed from
132///    a Solidity method signature, and the method takes the precompute handle
133///    and data offset as parameters.
134///  - `#[evm_method(signature = "...", convert)]`: The method selector is
135///    computed from the signature, the arguments are automatically decoded and
136///    passed to the marked method, which must have the appropriate number and
137///    type of arguments.
138#[proc_macro_attribute]
139pub fn evm_method(_args: TokenStream, input: TokenStream) -> TokenStream {
140    input
141}
142
143/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
144/// it only marks the function within a contract implementation that returns its address.
145///
146/// The method marked with this attribute should take no arguments and return
147/// an object of type `primitive_types::H160`.
148#[proc_macro_attribute]
149pub fn evm_contract_address(_args: TokenStream, input: TokenStream) -> TokenStream {
150    input
151}
152
153/// Constructs an `oasis_sdk::core::common::version::Version` from the Cargo.toml version.
154#[proc_macro]
155pub fn version_from_cargo(_input: TokenStream) -> TokenStream {
156    version_from_cargo::version_from_cargo().into()
157}