Replace JSON metadata with custom metadata structures (#766)

* Move module metadata from json string to custom metadata

* Revisit the metadata structures

1. Move the structures into the metadata crate.
2. Switch to using Cow/MaybeOwnedArray to support Encode/Decode

* Adapt to new metadata structures

* Convert event json metadata to new metadata structures

* Convert storage json metadata to new metadata structures

* Convert runtime metadata from json to new metadata structs

* Implements new metadata structures in client and runtime

* Fixes errors on `no_std`

* Fixes errors after rebasing master

* Do not use `Cow` anymore in metadata

Also replace `String` with our own type definition `StringBuf`.
This fixes compilation on `no_std`.

* Wrap `RuntimeMetadata` in `RuntimeMetadataVersioned` to support versioning

* Move metadata into `srml` and make core unaware of the implementation
This commit is contained in:
Bastian Köcher
2018-09-20 07:35:32 +02:00
committed by Gav Wood
parent 3c0da110f3
commit 5d64be26c3
22 changed files with 1138 additions and 843 deletions
+2 -3
View File
@@ -9,15 +9,14 @@ serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
parity-codec = { version = "1.1", default_features = false }
substrate-primitives = { path = "../../core/primitives", default_features = false }
substrate-metadata = { path = "../../core/metadata", default_features = false }
substrate-metadata = { path = "../metadata", default_features = false }
sr-std = { path = "../../core/sr-std", default_features = false }
sr-io = { path = "../../core/sr-io", default_features = false }
mashup = "0.1.7"
[dev-dependencies]
pretty_assertions = "0.5.1"
serde_json = { version = "1.0" }
parity-codec-derive = { version = "~1.0" }
parity-codec-derive = { version = "1.0" }
[features]
default = ["std"]
+141 -94
View File
@@ -23,6 +23,10 @@ pub use rstd::result;
#[cfg(feature = "std")]
use serde;
pub use codec::{Codec, Decode, Encode, Input, Output};
pub use substrate_metadata::{
ModuleMetadata, FunctionMetadata, DecodeDifferent,
CallMetadata, FunctionArgumentMetadata
};
pub type Result = result::Result<(), &'static str>;
@@ -306,7 +310,7 @@ macro_rules! decl_module {
d.dispatch(origin)
}
}
__dispatch_impl_json_metadata! {
__dispatch_impl_metadata! {
$mod_type $trait_instance $trait_name $call_type $origin_type
{$( $(#[doc = $doc_attr])* fn $fn_name($from $(, $param_name : $param )*) -> $result; )*}
}
@@ -461,15 +465,17 @@ macro_rules! __impl_outer_dispatch_common {
/// Implement the `json_metadata` function.
#[macro_export]
#[doc(hidden)]
macro_rules! __dispatch_impl_json_metadata {
macro_rules! __dispatch_impl_metadata {
(
$mod_type:ident $trait_instance:ident $trait_name:ident
$($rest:tt)*
) => {
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
pub fn json_metadata() -> &'static str {
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "call": "#,
__call_to_json!($($rest)*), " }")
pub fn metadata() -> $crate::dispatch::ModuleMetadata {
$crate::dispatch::ModuleMetadata {
name: $crate::dispatch::DecodeDifferent::Encode(stringify!($mod_type)),
call: __call_to_metadata!($($rest)*),
}
}
}
}
@@ -478,7 +484,7 @@ macro_rules! __dispatch_impl_json_metadata {
/// Convert the list of calls into their JSON representation, joined by ",".
#[macro_export]
#[doc(hidden)]
macro_rules! __call_to_json {
macro_rules! __call_to_metadata {
(
$call_type:ident $origin_type:ty
{$(
@@ -490,111 +496,111 @@ macro_rules! __call_to_json {
) -> $result:ty;
)*}
) => {
concat!(
r#"{ "name": ""#, stringify!($call_type),
r#"", "functions": {"#,
__functions_to_json!(""; 0; $origin_type; $(
$crate::dispatch::CallMetadata {
name: $crate::dispatch::DecodeDifferent::Encode(stringify!($call_type)),
functions: __functions_to_metadata!(0; $origin_type;; $(
fn $fn_name($from $(, $param_name: $param )* ) -> $result;
__function_doc_to_json!(""; $($doc_attr)*);
)*), " } }"
)
$( $doc_attr ),*;
)*),
}
};
}
/// Convert a list of functions into their JSON representation, joined by ",".
/// Convert a list of functions into a list of `FunctionMetadata` items.
#[macro_export]
#[doc(hidden)]
macro_rules! __functions_to_json {
macro_rules! __functions_to_metadata{
// ROOT
(
$prefix_str:tt;
$fn_id:expr;
$origin_type:ty;
$( $function_metadata:expr ),*;
fn $fn_name:ident(root
$(
, $param_name:ident : $param:ty
)*
) -> $result:ty;
$fn_doc:expr;
$($rest:tt)*
$( $fn_doc:expr ),*;
$( $rest:tt )*
) => {
concat!($prefix_str, " ",
__function_to_json!(
fn $fn_name(
$( $param_name : $param ),*
) -> $result;
$fn_doc;
$fn_id;
), __functions_to_json!(","; $fn_id + 1; $origin_type; $($rest)*)
)
__functions_to_metadata!(
$fn_id + 1; $origin_type;
$( $function_metadata, )* __function_to_metadata!(
fn $fn_name($( $param_name : $param ),*) -> $result; $( $fn_doc ),*; $fn_id;
);
$($rest)*
)
};
// NON ROOT
(
$prefix_str:tt;
$fn_id:expr;
$origin_type:ty;
$( $function_metadata:expr ),*;
fn $fn_name:ident(origin
$(
, $param_name:ident : $param:ty
)*
) -> $result:ty;
$fn_doc:expr;
$( $fn_doc:expr ),*;
$($rest:tt)*
) => {
concat!($prefix_str, " ",
__function_to_json!(
fn $fn_name(
origin: $origin_type
$(, $param_name : $param)*
) -> $result;
$fn_doc;
$fn_id;
), __functions_to_json!(","; $fn_id + 1; $origin_type; $($rest)*)
)
__functions_to_metadata!(
$fn_id + 1; $origin_type;
$( $function_metadata, )* __function_to_metadata!(
fn $fn_name(
origin: $origin_type
$( ,$param_name : $param )*
) -> $result; $( $fn_doc ),*; $fn_id;
);
$($rest)*
)
};
// BASE CASE
(
$prefix_str:tt;
$fn_id:expr;
$($origin_type:ty;)*
$origin_type:ty;
$( $function_metadata:expr ),*;
) => {
""
$crate::dispatch::DecodeDifferent::Encode(&[ $( $function_metadata ),* ])
}
}
/// Convert a function into its JSON representation.
/// Convert a function into its metadata representation.
#[macro_export]
#[doc(hidden)]
macro_rules! __function_to_json {
macro_rules! __function_to_metadata {
(
fn $fn_name:ident(
$first_param_name:ident : $first_param:ty $(, $param_name:ident : $param:ty)*
$($param_name:ident : $param:ty),*
) -> $result:ty;
$fn_doc:tt;
$( $fn_doc:expr ),*;
$fn_id:expr;
) => {
concat!(
r#"""#, stringify!($fn_id), r#"""#,
r#": { "name": ""#, stringify!($fn_name),
r#"", "params": [ "#,
concat!(r#"{ "name": ""#, stringify!($first_param_name), r#"", "type": ""#, stringify!($first_param), r#"" }"# ),
$crate::dispatch::FunctionMetadata {
id: $fn_id,
name: $crate::dispatch::DecodeDifferent::Encode(stringify!($fn_name)),
arguments: $crate::dispatch::DecodeDifferent::Encode(&[
$(
concat!(r#", { "name": ""#, stringify!($param_name), r#"", "type": ""#, stringify!($param), r#"" }"# ),
)*
r#" ], "description": ["#, $fn_doc, " ] }"
)
$crate::dispatch::FunctionArgumentMetadata {
name: $crate::dispatch::DecodeDifferent::Encode(stringify!($param_name)),
ty: $crate::dispatch::DecodeDifferent::Encode(stringify!($param)),
}
),*
]),
documentation: $crate::dispatch::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]),
}
};
(
fn $fn_name:ident() -> $result:ty;
$fn_doc:tt;
$( $fn_doc:expr ),*;
$fn_id:expr;
) => {
concat!(
r#"""#, stringify!($fn_id), r#"""#,
r#": { "name": ""#, stringify!($fn_name),
r#"", "params": [ "#,
r#" ], "description": ["#, $fn_doc, " ] }"
)
$crate::dispatch::FunctionMetadata {
id: $fn_id,
name: $crate::dispatch::DecodeDifferent::Encode(stringify!($fn_name)),
arguments: $crate::dispatch::DecodeDifferent::Encode(&[]),
documentation: $crate::dispatch::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]),
}
};
}
@@ -626,8 +632,6 @@ macro_rules! __function_doc_to_json {
#[allow(dead_code)]
mod tests {
use super::*;
use serde;
use serde_json;
pub trait Trait {
type Origin;
@@ -652,33 +656,78 @@ mod tests {
}
}
const EXPECTED_METADATA: &str = concat!(
r#"{ "name": "Module", "call": "#,
r#"{ "name": "Call", "functions": { "#,
r#""0": { "name": "aux_0", "params": [ "#,
r#"{ "name": "origin", "type": "T::Origin" }"#,
r#" ], "description": [ " Hi, this is a comment." ] }, "#,
r#""0 + 1": { "name": "aux_1", "params": [ "#,
r#"{ "name": "origin", "type": "T::Origin" }, "#,
r#"{ "name": "data", "type": "i32" }"#,
r#" ], "description": [ ] }, "#,
r#""0 + 1 + 1": { "name": "aux_2", "params": [ "#,
r#"{ "name": "origin", "type": "T::Origin" }, "#,
r#"{ "name": "data", "type": "i32" }, "#,
r#"{ "name": "data2", "type": "String" }"#,
r#" ], "description": [ ] }, "#,
r#""0 + 1 + 1 + 1": { "name": "aux_3", "params": [ "#,
r#" ], "description": [ ] }, "#,
r#""0 + 1 + 1 + 1 + 1": { "name": "aux_4", "params": [ "#,
r#"{ "name": "data", "type": "i32" }"#,
r#" ], "description": [ ] }"#,
r#" } }"#,
r#" }"#,
);
const EXPECTED_METADATA: ModuleMetadata = ModuleMetadata {
name: DecodeDifferent::Encode("Module"),
call: CallMetadata {
name: DecodeDifferent::Encode("Call"),
functions: DecodeDifferent::Encode(&[
FunctionMetadata {
id: 0,
name: DecodeDifferent::Encode("aux_0"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("origin"),
ty: DecodeDifferent::Encode("T::Origin"),
}
]),
documentation: DecodeDifferent::Encode(&[
" Hi, this is a comment."
])
},
FunctionMetadata {
id: 1,
name: DecodeDifferent::Encode("aux_1"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("origin"),
ty: DecodeDifferent::Encode("T::Origin"),
},
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("data"),
ty: DecodeDifferent::Encode("i32"),
}
]),
documentation: DecodeDifferent::Encode(&[]),
},
FunctionMetadata {
id: 2,
name: DecodeDifferent::Encode("aux_2"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("origin"),
ty: DecodeDifferent::Encode("T::Origin"),
},
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("data"),
ty: DecodeDifferent::Encode("i32"),
},
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("data2"),
ty: DecodeDifferent::Encode("String"),
}
]),
documentation: DecodeDifferent::Encode(&[]),
},
FunctionMetadata {
id: 3,
name: DecodeDifferent::Encode("aux_3"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[]),
},
FunctionMetadata {
id: 4,
name: DecodeDifferent::Encode("aux_4"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("data"),
ty: DecodeDifferent::Encode("i32"),
}
]),
documentation: DecodeDifferent::Encode(&[]),
}
]),
},
};
impl<T: Trait> Module<T> {
fn aux_0(_: T::Origin) -> Result {
@@ -710,9 +759,7 @@ mod tests {
#[test]
fn module_json_metadata() {
let metadata = Module::<TraitImpl>::json_metadata();
let metadata = Module::<TraitImpl>::metadata();
assert_eq!(EXPECTED_METADATA, metadata);
let _: serde::de::IgnoredAny =
serde_json::from_str(metadata).expect("Is valid json syntax");
}
}
+93 -78
View File
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
pub use substrate_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEncode};
/// Implement the `Event` for a module.
///
/// # Simple Event Example:
@@ -125,8 +127,8 @@ macro_rules! decl_event {
}
impl Event {
#[allow(dead_code)]
pub fn event_json_metadata() -> &'static str {
concat!("{", __events_to_json!(""; $( $events )* ), " }")
pub fn metadata() -> &'static [ $crate::event::EventMetadata ] {
__events_to_metadata!(; $( $events )* )
}
}
}
@@ -226,8 +228,8 @@ macro_rules! __decl_generic_event {
}
impl<$( $generic_param ),*> RawEvent<$( $generic_param ),*> {
#[allow(dead_code)]
pub fn event_json_metadata() -> &'static str {
concat!("{", __events_to_json!(""; $( $events )* ), " }")
pub fn metadata() -> &'static [$crate::event::EventMetadata] {
__events_to_metadata!(; $( $events )* )
}
}
}
@@ -235,36 +237,31 @@ macro_rules! __decl_generic_event {
#[macro_export]
#[doc(hidden)]
macro_rules! __events_to_json {
macro_rules! __events_to_metadata {
(
$prefix_str:expr;
$( $metadata:expr ),*;
$( #[doc = $doc_attr:tt] )*
$event:ident( $first_param:path $(, $param:path )* ),
$event:ident $( ( $( $param:path ),* ) )*,
$( $rest:tt )*
) => {
concat!($prefix_str, " ", "\"", stringify!($event), r#"": { "params": [ ""#,
stringify!($first_param), "\""
$(, concat!(", \"", stringify!($param), "\"") )*, r#" ], "description": ["#,
__function_doc_to_json!(""; $( $doc_attr )*), " ] }",
__events_to_json!(","; $( $rest )*)
__events_to_metadata!(
$( $metadata, )*
$crate::event::EventMetadata {
name: $crate::event::DecodeDifferent::Encode(stringify!($event)),
arguments: $crate::event::DecodeDifferent::Encode(&[
$( $( stringify!($param) ),* )*
]),
documentation: $crate::event::DecodeDifferent::Encode(&[
$( $doc_attr ),*
]),
};
$( $rest )*
)
};
(
$prefix_str:expr;
$( #[doc = $doc_attr:tt] )*
$event:ident,
$( $rest:tt )*
$( $metadata:expr ),*;
) => {
concat!($prefix_str, " ", "\"", stringify!($event),
r#"": { "params": null, "description": ["#,
__function_doc_to_json!(""; $( $doc_attr )*), " ] }",
__events_to_json!(","; $( $rest )*)
)
};
(
$prefix_str:expr;
) => {
""
&[ $( $metadata ),* ]
}
}
@@ -408,20 +405,21 @@ macro_rules! __impl_outer_event_json_metadata {
) => {
impl $runtime {
#[allow(dead_code)]
pub fn outer_event_json_metadata() -> (&'static str, &'static [(&'static str, fn() -> &'static str)]) {
static METADATA: &[(&str, fn() -> &'static str)] = &[
("system", $system::Event::event_json_metadata)
$(
, (
stringify!($module_name),
$module_name::Event $( ::<$generic_param> )*::event_json_metadata
)
)*
];
(
stringify!($event_name),
METADATA
)
pub fn outer_event_metadata() -> $crate::event::OuterEventMetadata {
$crate::event::OuterEventMetadata {
name: $crate::event::DecodeDifferent::Encode(stringify!($event_name)),
events: $crate::event::DecodeDifferent::Encode(&[
("system", $crate::event::FnEncode(system::Event::metadata))
$(
, (
stringify!($module_name),
$crate::event::FnEncode(
$module_name::Event $( ::<$generic_param> )* ::metadata
)
)
)*
])
}
}
}
}
@@ -430,8 +428,7 @@ macro_rules! __impl_outer_event_json_metadata {
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use serde;
use serde_json;
use super::*;
mod system {
pub trait Trait {
@@ -567,46 +564,64 @@ mod tests {
type Origin = u32;
}
const EXPECTED_METADATA: (&str, &[(&str, &str)]) = (
"TestEvent", &[
("system", r#"{ "SystemEvent": { "params": null, "description": [ ] } }"#),
("event_module",
concat!(
"{",
r#" "TestEvent": { "params": [ "Balance", "Origin" ], "description": [ " Hi, I am a comment." ] },"#,
r#" "EventWithoutParams": { "params": null, "description": [ " Dog" ] }"#,
" }"
)
const EXPECTED_METADATA: OuterEventMetadata = OuterEventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
events: DecodeDifferent::Encode(&[
(
"system",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("SystemEvent"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[]),
}
])
),
("event_module2",
concat!(
"{",
r#" "TestEvent": { "params": [ "BalanceRenamed" ], "description": [ ] },"#,
r#" "TestOrigin": { "params": [ "OriginRenamed" ], "description": [ ] }"#,
" }"
)
(
"event_module",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
arguments: DecodeDifferent::Encode(&[ "Balance", "Origin" ]),
documentation: DecodeDifferent::Encode(&[ " Hi, I am a comment." ])
},
EventMetadata {
name: DecodeDifferent::Encode("EventWithoutParams"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[ " Dog" ]),
},
])
),
("event_module3",
concat!(
"{",
r#" "HiEvent": { "params": null, "description": [ ] }"#,
" }"
)
(
"event_module2",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
arguments: DecodeDifferent::Encode(&[ "BalanceRenamed" ]),
documentation: DecodeDifferent::Encode(&[])
},
EventMetadata {
name: DecodeDifferent::Encode("TestOrigin"),
arguments: DecodeDifferent::Encode(&[ "OriginRenamed" ]),
documentation: DecodeDifferent::Encode(&[]),
},
])
),
]
);
(
"event_module3",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("HiEvent"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[])
}
])
)
])
};
#[test]
fn outer_event_json_metadata() {
let metadata = TestRuntime::outer_event_json_metadata();
assert_eq!(EXPECTED_METADATA.0, metadata.0);
assert_eq!(EXPECTED_METADATA.1.len(), metadata.1.len());
for (expected, got) in EXPECTED_METADATA.1.iter().zip(metadata.1.iter()) {
assert_eq!(expected.0, got.0);
assert_eq!(expected.1, got.1());
let _: serde::de::IgnoredAny =
serde_json::from_str(got.1()).expect(&format!("Is valid json syntax: {}", got.1()));
}
fn outer_event_metadata() {
assert_eq!(EXPECTED_METADATA, TestRuntime::outer_event_metadata());
}
}
+1 -3
View File
@@ -41,8 +41,6 @@ extern crate pretty_assertions;
#[macro_use]
extern crate serde_derive;
#[cfg(test)]
extern crate serde_json;
#[cfg(test)]
#[macro_use]
extern crate parity_codec_derive;
@@ -62,7 +60,7 @@ pub mod dispatch;
pub mod storage;
mod hashable;
#[macro_use]
mod event;
pub mod event;
#[macro_use]
pub mod metadata;
#[macro_use]
+129 -120
View File
@@ -14,38 +14,30 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use alloc;
pub use substrate_metadata::JsonMetadata;
pub use substrate_metadata::{
DecodeDifferent, FnEncode, RuntimeMetadata, RuntimeModuleMetadata
};
/// Make Box available on `std` and `no_std`.
pub type Box<T> = alloc::boxed::Box<T>;
/// Make Vec available on `std` and `no_std`.
pub type Vec<T> = alloc::vec::Vec<T>;
/// Implements the json metadata support for the given runtime and all its modules.
/// Implements the metadata support for the given runtime and all its modules.
///
/// Example:
/// ```compile_fail
/// impl_json_metadata!(for RUNTIME_NAME with modules MODULE0, MODULE2, MODULE3 with Storage);
/// impl_runtime_metadata!(for RUNTIME_NAME with modules MODULE0, MODULE2, MODULE3 with Storage);
/// ```
///
/// In this example, just `MODULE3` implements the `Storage` trait.
#[macro_export]
macro_rules! impl_json_metadata {
macro_rules! impl_runtime_metadata {
(
for $runtime:ident with modules
$( $rest:tt )*
) => {
impl $runtime {
pub fn json_metadata() -> $crate::metadata::Vec<$crate::metadata::JsonMetadata> {
let events = Self::outer_event_json_metadata();
__impl_json_metadata!($runtime;
$crate::metadata::JsonMetadata::Events {
name: events.0,
events: events.1,
};
$( $rest )*
)
pub fn metadata() -> $crate::metadata::RuntimeMetadata {
$crate::metadata::RuntimeMetadata {
outer_event: Self::outer_event_metadata(),
modules: __runtime_modules_to_metadata!($runtime;; $( $rest )*),
}
}
}
}
@@ -53,66 +45,50 @@ macro_rules! impl_json_metadata {
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_json_metadata {
macro_rules! __runtime_modules_to_metadata {
(
$runtime: ident;
$( $metadata:expr ),*;
$mod:ident::$module:ident,
$( $rest:tt )*
) => {
__impl_json_metadata!(
__runtime_modules_to_metadata!(
$runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::Module {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod)
$( $metadata, )* $crate::metadata::RuntimeModuleMetadata {
prefix: $crate::metadata::DecodeDifferent::Encode(stringify!($mod)),
module: $crate::metadata::DecodeDifferent::Encode(
$crate::metadata::FnEncode($mod::$module::<$runtime>::metadata)
),
storage: None,
};
$( $rest )*
)
};
(
$runtime: ident;
$( $metadata:expr ),*;
$mod:ident::$module:ident
) => {
__impl_json_metadata!(
$runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::Module {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod)
};
)
};
(
$runtime: ident;
$( $metadata:expr ),*;
$mod:ident::$module:ident with Storage,
$( $rest:tt )*
) => {
__impl_json_metadata!(
__runtime_modules_to_metadata!(
$runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::ModuleWithStorage {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod),
storage: $mod::$module::<$runtime>::store_json_metadata()
$( $metadata, )* $crate::metadata::RuntimeModuleMetadata {
prefix: $crate::metadata::DecodeDifferent::Encode(stringify!($mod)),
module: $crate::metadata::DecodeDifferent::Encode(
$crate::metadata::FnEncode($mod::$module::<$runtime>::metadata)
),
storage: Some($crate::metadata::DecodeDifferent::Encode(
$crate::metadata::FnEncode($mod::$module::<$runtime>::store_metadata)
)),
};
$( $rest )*
)
};
(
$runtime: ident;
$( $metadata:expr ),*;
$mod:ident::$module:ident with Storage
) => {
__impl_json_metadata!(
$runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::ModuleWithStorage {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod),
storage: $mod::$module::<$runtime>::store_json_metadata()
};
)
};
(
$runtime:ident;
$( $metadata:expr ),*;
) => {
<[_]>::into_vec($crate::metadata::Box::new([ $( $metadata ),* ]))
$crate::metadata::DecodeDifferent::Encode(&[ $( $metadata ),* ])
};
}
@@ -121,9 +97,11 @@ macro_rules! __impl_json_metadata {
#[allow(dead_code)]
mod tests {
use super::*;
use serde;
use serde_json;
use substrate_metadata::JsonMetadataDecodable;
use substrate_metadata::{
EventMetadata, OuterEventMetadata, RuntimeModuleMetadata, CallMetadata, ModuleMetadata,
StorageFunctionModifier, StorageFunctionType, FunctionMetadata, FunctionArgumentMetadata,
StorageMetadata, StorageFunctionMetadata,
};
use codec::{Decode, Encode};
mod system {
@@ -219,79 +197,110 @@ mod tests {
type Origin = u32;
}
fn system_event_json() -> &'static str {
r#"{ "SystemEvent": { "params": null, "description": [ ] } }"#
}
fn event_module_event_json() -> &'static str {
r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ " Hi, I am a comment." ] } }"#
}
fn event_module2_event_json() -> &'static str {
r#"{ "TestEvent": { "params": [ "Balance" ], "description": [ ] } }"#
}
impl_json_metadata!(
impl_runtime_metadata!(
for TestRuntime with modules
event_module::Module,
event_module2::ModuleWithStorage with Storage
event_module2::ModuleWithStorage with Storage,
);
const EXPECTED_METADATA: &[JsonMetadata] = &[
JsonMetadata::Events {
name: "TestEvent",
events: &[
("system", system_event_json),
("event_module", event_module_event_json),
("event_module2", event_module2_event_json),
]
const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata {
outer_event: OuterEventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
events: DecodeDifferent::Encode(&[
(
"system",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("SystemEvent"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[]),
}
])
),
(
"event_module",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
arguments: DecodeDifferent::Encode(&["Balance"]),
documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."])
}
])
),
(
"event_module2",
FnEncode(|| &[
EventMetadata {
name: DecodeDifferent::Encode("TestEvent"),
arguments: DecodeDifferent::Encode(&["Balance"]),
documentation: DecodeDifferent::Encode(&[])
}
])
)
]),
},
JsonMetadata::Module {
module: concat!(
r#"{ "name": "Module", "call": "#,
r#"{ "name": "Call", "functions": "#,
r#"{ "0": { "name": "aux_0", "params": [ "#,
r#"{ "name": "origin", "type": "T::Origin" } ], "#,
r#""description": [ ] } } } }"#
),
prefix: "event_module"
},
JsonMetadata::ModuleWithStorage {
module: r#"{ "name": "ModuleWithStorage", "call": { "name": "Call", "functions": { } } }"#,
prefix: "event_module2",
storage: concat!(
r#"{ "prefix": "TestStorage", "items": { "#,
r#""StorageMethod": { "description": [ ], "modifier": null, "type": "u32" }"#,
r#" } }"#
)
}
];
modules: DecodeDifferent::Encode(&[
RuntimeModuleMetadata {
prefix: DecodeDifferent::Encode("event_module"),
module: DecodeDifferent::Encode(FnEncode(||
ModuleMetadata {
name: DecodeDifferent::Encode("Module"),
call: CallMetadata {
name: DecodeDifferent::Encode("Call"),
functions: DecodeDifferent::Encode(&[
FunctionMetadata {
id: 0,
name: DecodeDifferent::Encode("aux_0"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("origin"),
ty: DecodeDifferent::Encode("T::Origin"),
}
]),
documentation: DecodeDifferent::Encode(&[]),
}
])
}
}
)),
storage: None,
},
RuntimeModuleMetadata {
prefix: DecodeDifferent::Encode("event_module2"),
module: DecodeDifferent::Encode(FnEncode(||
ModuleMetadata {
name: DecodeDifferent::Encode("ModuleWithStorage"),
call: CallMetadata {
name: DecodeDifferent::Encode("Call"),
functions: DecodeDifferent::Encode(&[])
}
}
)),
storage: Some(DecodeDifferent::Encode(FnEncode(||
StorageMetadata {
prefix: DecodeDifferent::Encode("TestStorage"),
functions: DecodeDifferent::Encode(&[
StorageFunctionMetadata {
name: DecodeDifferent::Encode("StorageMethod"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
}
])
}
))),
}
])
};
#[test]
fn runtime_json_metadata() {
let metadata = TestRuntime::json_metadata();
assert_eq!(EXPECTED_METADATA, &metadata[..]);
}
fn runtime_metadata() {
let metadata = TestRuntime::metadata();
assert_eq!(EXPECTED_METADATA, metadata);
#[test]
fn json_metadata_encode_and_decode() {
let metadata = TestRuntime::json_metadata();
let metadata_encoded = metadata.encode();
let metadata_decoded = Vec::<JsonMetadataDecodable>::decode(&mut &metadata_encoded[..]);
let metadata_decoded = RuntimeMetadata::decode(&mut &metadata_encoded[..]);
assert_eq!(&metadata_decoded.unwrap()[..], &metadata[..]);
}
#[test]
fn into_json_string_is_valid_json() {
let metadata = TestRuntime::json_metadata();
let metadata_encoded = metadata.encode();
let metadata_decoded = Vec::<JsonMetadataDecodable>::decode(&mut &metadata_encoded[..]);
for mdata in metadata_decoded.unwrap().into_iter() {
let json = mdata.into_json_string();
let _: serde::de::IgnoredAny =
serde_json::from_str(&json.1).expect(&format!("Is valid json syntax: {}", json.1));
}
assert_eq!(metadata, metadata_decoded.unwrap());
}
}
+10 -10
View File
@@ -275,7 +275,7 @@ macro_rules! construct_runtime {
$name: $module::{ $( $modules $( <$modules_generic> )* ),* }
),*;
);
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
;
;
@@ -664,7 +664,7 @@ macro_rules! __decl_outer_dispatch {
#[macro_export]
#[doc(hidden)]
macro_rules! __decl_json_metadata {
macro_rules! __decl_runtime_metadata {
(
$runtime:ident;
;
@@ -676,7 +676,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
$module { Module, };
$( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -699,7 +699,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module with Storage };
@@ -721,7 +721,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
$module { , Storage };
$( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -744,7 +744,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module with Storage };
@@ -766,7 +766,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
$( $current_module { $( $current_module_storage )* } )*;
$( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -787,7 +787,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module };
@@ -807,7 +807,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*;
) => {
__decl_json_metadata!(
__decl_runtime_metadata!(
$runtime;
;
$( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -824,7 +824,7 @@ macro_rules! __decl_json_metadata {
$( $parsed_modules:ident { Module $( with $parsed_storage:ident )* } ),*;
;
) => {
impl_json_metadata!(
impl_runtime_metadata!(
for $runtime with modules
$( $parsed_modules::Module $(with $parsed_storage)*, )*
);
+448 -264
View File
@@ -53,6 +53,11 @@ pub use rstd::borrow::Borrow;
#[doc(hidden)]
pub use rstd::marker::PhantomData;
pub use substrate_metadata::{
DecodeDifferent, StorageMetadata, StorageFunctionMetadata,
StorageFunctionType, StorageFunctionModifier
};
/// Abstraction around storage.
pub trait Storage {
/// true if the key exists in storage.
@@ -530,7 +535,7 @@ macro_rules! decl_storage {
}
impl<$traitinstance: $traittype> $modulename<$traitinstance> {
__impl_store_fns!($traitinstance $($t)*);
__impl_store_json_metadata!($cratename; $($t)*);
__impl_store_metadata!($cratename; $($t)*);
}
};
(
@@ -1080,390 +1085,427 @@ macro_rules! __impl_store_item {
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_store_json_metadata {
macro_rules! __impl_store_metadata {
(
$cratename:ident;
$($rest:tt)*
) => {
pub fn store_json_metadata() -> &'static str {
concat!(r#"{ "prefix": ""#, stringify!($cratename), r#"", "items": {"#,
__store_functions_to_json!(""; $($rest)*), " } }")
pub fn store_metadata() -> $crate::storage::generator::StorageMetadata {
$crate::storage::generator::StorageMetadata {
prefix: $crate::storage::generator::DecodeDifferent::Encode(stringify!($cratename)),
functions: __store_functions_to_metadata!(; $( $rest )* ),
}
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __store_functions_to_json {
macro_rules! __store_functions_to_metadata {
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
default $ty:ty; $($t:tt)*
$name:ident : default $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
default $ty:ty; $($t:tt)*
pub $name:ident : default $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
required $ty:ty; $($t:tt)*
$name:ident : required $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
required $ty:ty; $($t:tt)*
pub $name:ident : required $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
);
$( $t )*
)
};
// simple values
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
$ty:ty; $($t:tt)*
$name:ident : $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
$ty:ty; $($t:tt)*
pub $name:ident : $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) :
default $ty:ty; $($t:tt)*
default $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
default $ty:ty; $($t:tt)*
default $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) :
required $ty:ty; $($t:tt)*
required $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
required $ty:ty; $($t:tt)*
required $ty:ty;
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) :
$ty:ty; $($t:tt)*
$name:ident get($getfn:ident) : $ty:ty;
$( $t:tt )*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
$ty:ty; $($t:tt)*
pub $name:ident get($getfn:ident) : $ty:ty;
$( $t:tt )*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
);
$( $t )*
)
};
// maps
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
default map [$kty:ty => $ty:ty]; $($t:tt)*
default map [$kty:ty => $ty:ty];
$( $t:tt )*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
default map [$kty:ty => $ty:ty]; $($t:tt)*
default map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
required map [$kty:ty => $ty:ty]; $($t:tt)*
required map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
required map [$kty:ty => $ty:ty]; $($t:tt)*
required map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident :
map [$kty:ty => $ty:ty]; $($t:tt)*
map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident :
map [$kty:ty => $ty:ty]; $($t:tt)*
map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $name:ident get($getfn:ident) :
default map [$kty:ty => $ty:ty]; $($t:tt)*
default map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
default map [$kty:ty => $ty:ty]; $($t:tt)*
default map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), default
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $name:ident get($getfn:ident) :
required map [$kty:ty => $ty:ty]; $($t:tt)*
required map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
);
$( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
required map [$kty:ty => $ty:ty]; $($t:tt)*
required map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty), required
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
); $( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) :
map [$kty:ty => $ty:ty]; $($t:tt)*
map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
); $( $t )*
)
};
(
$prefix_str:tt;
$( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) :
map [$kty:ty => $ty:ty]; $($t:tt)*
map [$kty:ty => $ty:ty];
$($t:tt)*
) => {
concat!(
__store_function_to_json!($prefix_str,
__function_doc_to_json!(""; $($doc_attr)*),
$name, __store_type_to_json!($kty, $ty)
),
__store_functions_to_json!(","; $($t)*)
__store_functions_to_metadata!(
$( $metadata, )*
__store_function_to_metadata!(
$( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
); $( $t )*
)
};
($prefix_str:tt;) => { "" }
}
#[macro_export]
#[doc(hidden)]
macro_rules! __store_function_to_json {
($prefix_str:tt, $fn_doc:expr, $name:ident, $type:expr, $modifier:ident) => {
__store_function_to_json!($prefix_str; $fn_doc; $name; $type;
concat!("\"", stringify!($modifier), "\""))
};
($prefix_str:tt, $fn_doc:expr, $name:ident, $type:expr) => {
__store_function_to_json!($prefix_str; $fn_doc; $name; $type; "null")
};
($prefix_str:tt; $fn_doc:expr; $name:ident; $type:expr; $modifier:expr) => {
concat!($prefix_str, " \"", stringify!($name), "\": { ",
r#""description": ["#, $fn_doc, " ], ",
r#""modifier": "#, $modifier, r#", "type": "#, $type, r#" }"#
)
(
$( $metadata:expr ),*;
) => {
$crate::storage::generator::DecodeDifferent::Encode(&[
$( $metadata ),*
])
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __store_type_to_json {
macro_rules! __store_function_to_metadata {
($( $fn_doc:expr ),*; $name:ident, $type:expr, required) => {
__store_function_to_metadata!(
$( $fn_doc ),*; $name; $type;
$crate::storage::generator::StorageFunctionModifier::Required
)
};
($( $fn_doc:expr ),*; $name:ident, $type:expr, default) => {
__store_function_to_metadata!(
$( $fn_doc ),*; $name; $type;
$crate::storage::generator::StorageFunctionModifier::Default
)
};
($( $fn_doc:expr ),*; $name:ident, $type:expr) => {
__store_function_to_metadata!(
$( $fn_doc ),*; $name; $type;
$crate::storage::generator::StorageFunctionModifier::None
)
};
($( $fn_doc:expr ),*; $name:ident; $type:expr; $modifier:expr) => {
$crate::storage::generator::StorageFunctionMetadata {
name: $crate::storage::generator::DecodeDifferent::Encode(stringify!($name)),
modifier: $modifier,
ty: $type,
documentation: $crate::storage::generator::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]),
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __store_type_to_metadata {
($name:ty) => {
concat!("\"", stringify!($name), "\"")
$crate::storage::generator::StorageFunctionType::Plain(
$crate::storage::generator::DecodeDifferent::Encode(stringify!($name)),
)
};
($key: ty, $value:ty) => {
concat!(r#"{ "key": ""#, stringify!($key), r#"", "value": ""#,
stringify!($value), "\" }")
$crate::storage::generator::StorageFunctionType::Map {
key: $crate::storage::generator::DecodeDifferent::Encode(stringify!($key)),
value: $crate::storage::generator::DecodeDifferent::Encode(stringify!($value)),
}
}
}
@@ -1475,8 +1517,6 @@ mod tests {
use std::cell::RefCell;
use codec::Codec;
use super::*;
use serde;
use serde_json;
impl Storage for RefCell<HashMap<Vec<u8>, Vec<u8>>> {
fn exists(&self, key: &[u8]) -> bool {
@@ -1580,7 +1620,6 @@ mod tests {
GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ];
pub PUBMAPU32Required : required map [ u32 => String ];
pub GETPUBMAPU32Required get(map_pub_get_u32_required): required map [ u32 => String ];
}
}
@@ -1590,41 +1629,186 @@ mod tests {
type Origin = u32;
}
const EXPECTED_METADATA: &str = concat!(
r#"{ "prefix": "TestStorage", "items": { "#,
r#""U32": { "description": [ " Hello, this is doc!" ], "modifier": null, "type": "u32" }, "#,
r#""GETU32": { "description": [ ], "modifier": null, "type": "u32" }, "#,
r#""PUBU32": { "description": [ ], "modifier": null, "type": "u32" }, "#,
r#""GETPUBU32": { "description": [ ], "modifier": null, "type": "u32" }, "#,
r#""U32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#,
r#""GETU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#,
r#""PUBU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#,
r#""GETPUBU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#,
r#""U32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#,
r#""GETU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#,
r#""PUBU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#,
r#""GETPUBU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#,
r#""MAPU32": { "description": [ ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#,
r#""GETMAPU32": { "description": [ " Hello, this is doc!", " Hello, this is doc 2!" ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#,
r#""PUBMAPU32": { "description": [ ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#,
r#""GETPUBMAPU32": { "description": [ ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#,
r#""MAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#,
r#""GETMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#,
r#""PUBMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#,
r#""GETPUBMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#,
r#""MAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#,
r#""GETMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#,
r#""PUBMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#,
r#""GETPUBMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }"#,
" } }"
);
const EXPECTED_METADATA: StorageMetadata = StorageMetadata {
prefix: DecodeDifferent::Encode("TestStorage"),
functions: DecodeDifferent::Encode(&[
StorageFunctionMetadata {
name: DecodeDifferent::Encode("U32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[ " Hello, this is doc!" ]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("U32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("U32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("MAPU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETMAPU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[
" Hello, this is doc!", " Hello, this is doc 2!"
]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBMAPU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBMAPU32"),
modifier: StorageFunctionModifier::None,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("MAPU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETMAPU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBMAPU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBMAPU32Default"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("MAPU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETMAPU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("PUBMAPU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
},
StorageFunctionMetadata {
name: DecodeDifferent::Encode("GETPUBMAPU32Required"),
modifier: StorageFunctionModifier::Required,
ty: StorageFunctionType::Map{
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("String")
},
documentation: DecodeDifferent::Encode(&[]),
}
])
};
#[test]
fn store_json_metadata() {
let metadata = Module::<TraitImpl>::store_json_metadata();
fn store_metadata() {
let metadata = Module::<TraitImpl>::store_metadata();
assert_eq!(EXPECTED_METADATA, metadata);
let _: serde::de::IgnoredAny =
serde_json::from_str(metadata).expect("Is valid json syntax");
}
}