Skip to content

Commit

Permalink
#![deny(missing_docs)] for sov_modules_macros
Browse files Browse the repository at this point in the history
  • Loading branch information
neysofu committed Jul 18, 2023
1 parent e41caa9 commit 6ce3baa
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 42 deletions.
7 changes: 5 additions & 2 deletions module-system/sov-modules-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ name = "tests"
path = "tests/all_tests.rs"

[dev-dependencies]
serde_json = "1"
jsonrpsee = { workspace = true, features = ["macros", "http-client", "server"] }
tempfile = { workspace = true }
trybuild = "1.0"

sov-modules-api = { path = "../sov-modules-api", version = "0.1", default-features = false }
jsonrpsee = { workspace = true, features = ["macros", "http-client", "server"] }
sov-state = { path = "../sov-state", version = "0.1", default-features = false }
tempfile = { workspace = true }
sov-bank = { path = "../module-implementations/sov-bank", version = "0.1" }

[dependencies]
anyhow = { workspace = true }
Expand Down
132 changes: 92 additions & 40 deletions module-system/sov-modules-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//! Procedural macros to assist in the creation of Sovereign modules.

#![deny(missing_docs)]
#![feature(log_syntax)]

mod cli_parser;
mod common;
mod default_runtime;
Expand All @@ -17,31 +21,44 @@ use proc_macro::TokenStream;
use rpc::ExposeRpcMacro;
use syn::parse_macro_input;

/// Derives the `sov-modules-api::ModuleInfo` implementation for the underlying type.
/// Derives the [`sov_modules_api::ModuleInfo`] trait for the underlying `struct`.
///
/// The underlying type must respect the following conditions, or compilation
/// will fail:
/// - It must be a named `struct`. Tuple `struct`s, `enum`s, and others are
/// not supported.
/// - It must have *exactly one* field with the `#[address]` attribute. This field
/// represents the **module address**.
/// - All other fields must have either the `#[state]` or `#[module]` attribute.
/// - `#[state]` is used for state members.
/// - `#[module]` is used for module members.
///
/// In addition to implementing [`sov_modules_api::ModuleInfo`], this macro will
/// also generate so-called "prefix" methods. See the [`sov_modules_api`] docs
/// for more information about prefix methods.
///
/// See `sov-modules-api` for definition of `prefix`.
/// ## Example
///
/// ``` ignore
/// #[derive(ModuleInfo)]
/// pub(crate) struct TestModule<C: Context> {
/// #[state]
/// pub test_state1: TestState<C::Storage>,
/// ```
/// use sov_modules_macros::ModuleInfo;
/// use sov_modules_api::{Context, ModuleInfo};
/// use sov_state::StateMap;
///
/// #[derive(ModuleInfo)]
/// struct TestModule<C: Context> {
/// #[address]
/// admin: C::Address,
///
/// #[state]
/// pub test_state2: TestState<C::Storage>,
/// }
/// pub state_map: StateMap<String, u32>,
/// }
///
/// // You can then get the prefix of `state_map` like this:
/// fn get_prefix<C: Context>(some_storage: C::Storage) {
/// let test_struct = TestModule::<C>::default();
/// let prefix1 = test_struct.state_map.prefix();
/// }
/// ```
/// allows getting a prefix of a member field like:
/// ```ignore
/// let test_struct = <TestModule::<SomeContext> as sov_modules_api::ModuleInfo>::new(some_storage);
/// let prefix1 = test_struct.test_state1.prefix;
/// ````
/// ## Attributes
///
/// * `state` - attribute for state members
/// * `module` - attribute for module members
/// * `address` - attribute for module address
#[proc_macro_derive(ModuleInfo, attributes(state, module, address))]
pub fn module_info(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input);
Expand All @@ -61,7 +78,8 @@ pub fn default_runtime(input: TokenStream) -> TokenStream {
handle_macro_error(default_config_macro.derive_default_runtime(input))
}

/// Derives the `sov-modules-api::Genesis` implementation for the underlying type.
/// Derives the [`sov_modules_api::Genesis`] trait for the underlying runtime
/// `struct`.
#[proc_macro_derive(Genesis)]
pub fn genesis(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input);
Expand All @@ -70,7 +88,7 @@ pub fn genesis(input: TokenStream) -> TokenStream {
handle_macro_error(genesis_macro.derive_genesis(input))
}

/// Derives the `sov-modules-api::DispatchCall` implementation for the underlying type.
/// Derives the [`sov_modules_api::DispatchCall`] trait for the underlying type.
#[proc_macro_derive(DispatchCall, attributes(serialization))]
pub fn dispatch_call(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input);
Expand All @@ -90,8 +108,9 @@ pub fn dispatch_call(input: TokenStream) -> TokenStream {
/// use sov_modules_api::default_context::ZkDefaultContext;
/// use sov_modules_macros::{ModuleInfo, ModuleCallJsonSchema};
/// use sov_state::StateMap;
/// use sov_bank::call::CallMessage;
///
/// #[derive(ModuleInfo, ModuleCallJsonSchema, schemars::JsonSchema)]
/// #[derive(ModuleInfo, ModuleCallJsonSchema)]
/// struct TestModule<C: Context> {
/// #[address]
/// admin: C::Address,
Expand All @@ -103,6 +122,7 @@ pub fn dispatch_call(input: TokenStream) -> TokenStream {
/// impl<C: Context> Module for TestModule<C> {
/// type Context = C;
/// type Config = PhantomData<C>;
/// type CallMessage = CallMessage<C>;
/// }
///
/// println!("JSON Schema: {}", TestModule::<ZkDefaultContext>::json_schema());
Expand All @@ -122,7 +142,7 @@ pub fn codec(input: TokenStream) -> TokenStream {
handle_macro_error(codec_macro.derive_message_codec(input))
}

/// Derive a `jsonrpsee` implementation for the underlying type. Any code relying on this macro
/// Derives a [`jsonrpsee`] implementation for the underlying type. Any code relying on this macro
/// must take jsonrpsee as a dependency with at least the following features enabled: `["macros", "client-core", "server"]`.
///
/// Syntax is identical to `jsonrpsee`'s `#[rpc]` execept that:
Expand All @@ -131,42 +151,58 @@ pub fn codec(input: TokenStream) -> TokenStream {
/// 3. `#[method]` is renamed to with `#[rpc_method]` to avoid import confusion and clarify the purpose of the annotation
///
/// ## Example
/// ```rust,ignore
/// struct MyModule {};
/// ```
/// use sov_modules_macros::{rpc_gen, ModuleInfo};
/// use sov_modules_api::Context;
///
/// #[derive(ModuleInfo)]
/// struct MyModule<C: Context> {
/// #[address]
/// addr: C::Address,
/// // ...
/// }
///
/// #[rpc_gen(client, server, namespace ="myNamespace")]
/// impl MyModule {
/// #[rpc_method(name = "myMethod")]
/// #[rpc_gen(client, server, namespace = "myNamespace")]
/// impl<C: Context> MyModule<C> {
/// #[rpc_method(name = "myMethod")]
/// fn my_method(&self, param: u32) -> u32 {
/// 1
/// 1
/// }
/// }
/// ```
///
/// This is exactly equivalent to hand-writing
/// ```rust,ignore
///
/// ```
/// use sov_modules_macros::{rpc_gen, ModuleInfo};
/// use sov_modules_api::Context;
/// use sov_state::WorkingSet;
///
/// #[derive(ModuleInfo)]
/// struct MyModule<C: Context> {
/// ...
/// #[address]
/// addr: C::Address,
/// // ...
/// };
///
/// impl MyModule {
/// impl<C: Context> MyModule<C> {
/// fn my_method(&self, working_set: &mut WorkingSet<C::Storage>, param: u32) -> u32 {
/// 1
/// }
/// }
///
/// #[jsonrpsee::rpc(client, server, namespace ="myNamespace")]
/// #[jsonrpsee::proc_macros::rpc(client, server, namespace ="myNamespace")]
/// pub trait MyModuleRpc {
/// #[jsonrpsee::method(name = "myMethod")]
/// fn my_method(&self, param: u32) -> Result<u32, jsonrpsee::Error>;
/// #[method(name = "health")]
/// fn health() -> Result<(), jsonrpsee::Error> {
/// Ok(())
/// }
/// #[method(name = "myMethod")]
/// fn my_method(&self, param: u32) -> Result<u32, jsonrpsee::core::Error>;
///
/// #[method(name = "health")]
/// fn health(&self) -> Result<(), jsonrpsee::core::Error> {
/// Ok(())
/// }
/// }
/// ```
///
///
/// This proc macro also generates an implementation trait intended to be used by a Runtime struct. This trait
/// is named `MyModuleRpcImpl`, and allows a Runtime to be converted into a functional RPC server
/// by simply implementing the two required methods - `get_backing_impl(&self) -> MyModule` and `get_working_set(&self) -> ::sov_modules_api::WorkingSet<C>`
Expand Down Expand Up @@ -205,6 +241,22 @@ pub fn expose_rpc(attr: TokenStream, input: TokenStream) -> TokenStream {
handle_macro_error(expose_macro.generate_rpc(original, input, context_type))
}

/// Generates a CLI arguments parser for the specified runtime.
///
/// ## Examples
/// ```
/// use sov_modules_api::Context;
/// use sov_modules_api::default_context::DefaultContext;
/// use sov_modules_macros::{DispatchCall, MessageCodec, cli_parser};
///
/// #[derive(DispatchCall, MessageCodec)]
/// #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)]
/// #[cli_parser(DefaultContext)]
/// pub struct Runtime<C: Context> {
/// pub bank: sov_bank::Bank<C>,
/// // ...
/// }
/// ```
#[proc_macro_attribute]
pub fn cli_parser(attr: TokenStream, input: TokenStream) -> TokenStream {
let context_type = parse_macro_input!(attr);
Expand Down

0 comments on commit 6ce3baa

Please sign in to comment.