1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#![feature(proc_macro_diagnostic)]
#![deny(rust_2018_idioms)]

use proc_macro::TokenStream;

mod error_derive;
mod event_derive;
mod generators;
mod module_derive;
#[cfg(test)]
mod test_utils;
mod version_from_cargo;

/// Emits a compile-time error `msg` from a macro, and uses the span of the
/// macro invocation if possible. If span info is not available (should only
/// happen in unit tests), panics with `msg`.
fn emit_compile_error<S: Into<String> + Clone + std::panic::RefUnwindSafe>(msg: S) -> ! {
    std::panic::catch_unwind(|| {
        proc_macro2::Span::call_site()
            .unwrap()
            .error(msg.clone().into())
            .emit();
    })
    .ok()
    .or_else(|| {
        panic!("{}", msg.into());
    });
    unreachable!(); // error().emit() already halts compilation, but type checker doesn't know that
}

/// Derives the `Event` trait on an enum.
#[proc_macro_derive(Event, attributes(sdk_event))]
pub fn event_derive(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    event_derive::derive_event(input).into()
}

/// Derives the `Error` trait on an enum.
// The helper attribute is `sdk_error` to avoid conflict with `thiserror::Error`.
#[proc_macro_derive(Error, attributes(sdk_error, source, from))]
pub fn error_derive(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);
    error_derive::derive_error(input).into()
}

/// Derives traits from a non-trait `impl` block (rather than from a `struct`).
///
/// Only the `Module` trait is supported. In other words, given an `impl MyModule` block, the macro
/// derives implementations needed for implementing a module.
/// See also the `#[handler]` and `#[migration]` attributes.
#[proc_macro_attribute]
pub fn sdk_derive(args: TokenStream, input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::ItemImpl);
    if args.to_string() == "Module" {
        module_derive::derive_module(input).into()
    } else {
        emit_compile_error("#[sdk_derive] only supports #[sdk_derive(Module)]");
    }
}

/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anyting on its own;
/// it only marks functions that represent a paratime method handler.
/// The permitted forms are:
///  - `#[handler(call = "my_module.MyCall")]`: Marks a function that handles
///        the "my_module.MyCall" call and can be passed to
///        oasis_runtime_sdk::module::dispatch_call.
///  - `#[handler(prefetch = "my_module.MyCall")]`: Marks a function that handles
///        the request to prefetch any data ahead of the "my_module.MyCall" call.
///        Its signature should be `Fn(
///          add_prefix: &mut dyn FnMut(Prefix) -> (),
///          body: cbor::Value,
///          auth_info: &AuthInfo,
///        ) -> Result<(), oasis_runtime_sdk::error::RuntimeError>`
///  - `#[handler(query = "my_module.MyQuery")]`: Marks a function that handles
///        the "my_module.MyQuery" query and can be passed to
///        oasis_runtime_sdk::module::dispatch_query.
///  - `#[handler(message_result = "my_module.MyMR")]`: Marks a function that handles
///        the "my_module.MyMR" message result and can be passed to
///        oasis_runtime_sdk::module::dispatch_message_result.
///
/// Query handler can also contain the `expensive` tag. Example:
/// `#[handler(query = "my_module.MyQuery", expensive)]`.
/// Queries tagged `expensive` can be enabled/disabled are disabled by default to avoid
/// excessive costs to the node operator. This can be overridden in the node config.
///
/// NOTE: This attribute is parsed by the `#[sdk_derive(...)]` macro, which cannot
/// interpret the attribute name semantically. Use `#[handler]`, not
/// `#[oasis_runtime_sdk_macros::handler]` or other paths/aliases.
#[proc_macro_attribute]
pub fn handler(_args: TokenStream, input: TokenStream) -> TokenStream {
    input
}

/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
/// it only marks functions that represent a module state migration.
///
/// The permitted forms are:
///  - `#[migration(init)]`: Marks the initial (genesis) migration.
///  - `#[migration(from = v)]`: Marks a migration from version v to v+1, where v is
///    a non-negative integer.
#[proc_macro_attribute]
pub fn migration(_args: TokenStream, input: TokenStream) -> TokenStream {
    input
}

/// Constructs an `oasis_sdk::core::common::version::Version` from the Cargo.toml version.
#[proc_macro]
pub fn version_from_cargo(_input: TokenStream) -> TokenStream {
    version_from_cargo::version_from_cargo().into()
}