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()
}