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
+3 -2
View File
@@ -2578,7 +2578,6 @@ dependencies = [
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 0.1.0", "sr-io 0.1.0",
"sr-std 0.1.0", "sr-std 0.1.0",
"substrate-metadata 0.1.0", "substrate-metadata 0.1.0",
@@ -2742,7 +2741,6 @@ dependencies = [
"substrate-bft 0.1.0", "substrate-bft 0.1.0",
"substrate-executor 0.1.0", "substrate-executor 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-metadata 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
"substrate-state-machine 0.1.0", "substrate-state-machine 0.1.0",
"substrate-telemetry 0.3.0", "substrate-telemetry 0.3.0",
@@ -2844,6 +2842,9 @@ name = "substrate-metadata"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
+1 -1
View File
@@ -28,7 +28,6 @@ members = [
"core/executor", "core/executor",
"core/extrinsic-pool", "core/extrinsic-pool",
"core/keyring", "core/keyring",
"core/metadata",
"core/misbehavior-check", "core/misbehavior-check",
"core/network", "core/network",
"core/primitives", "core/primitives",
@@ -46,6 +45,7 @@ members = [
"srml/democracy", "srml/democracy",
"srml/example", "srml/example",
"srml/executive", "srml/executive",
"srml/metadata",
"core/sr-primitives", "core/sr-primitives",
"srml/session", "srml/session",
"srml/staking", "srml/staking",
-1
View File
@@ -18,7 +18,6 @@ parity-codec = { version = "1.1" }
substrate-executor = { path = "../executor" } substrate-executor = { path = "../executor" }
substrate-primitives = { path = "../primitives" } substrate-primitives = { path = "../primitives" }
sr-io = { path = "../sr-io" } sr-io = { path = "../sr-io" }
substrate-metadata = { path = "../metadata" }
sr-primitives = { path = "../sr-primitives" } sr-primitives = { path = "../sr-primitives" }
substrate-state-machine = { path = "../state-machine" } substrate-state-machine = { path = "../state-machine" }
substrate-keyring = { path = "../../core/keyring" } substrate-keyring = { path = "../../core/keyring" }
+3 -49
View File
@@ -23,7 +23,6 @@ use primitives::AuthorityId;
use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}}; use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor};
use runtime_primitives::BuildStorage; use runtime_primitives::BuildStorage;
use substrate_metadata::JsonMetadataDecodable;
use primitives::{Blake2Hasher, RlpCodec, H256}; use primitives::{Blake2Hasher, RlpCodec, H256};
use primitives::storage::{StorageKey, StorageData}; use primitives::storage::{StorageKey, StorageData};
use primitives::storage::well_known_keys; use primitives::storage::well_known_keys;
@@ -254,26 +253,9 @@ impl<B, E, Block> Client<B, E, Block> where
&self.executor &self.executor
} }
/// Returns the runtime metadata as JSON. /// Returns the runtime metadata.
pub fn json_metadata(&self, id: &BlockId<Block>) -> error::Result<String> { pub fn metadata(&self, id: &BlockId<Block>) -> error::Result<Vec<u8>> {
self.executor.call(id, "json_metadata",&[]) self.executor.call(id, "metadata",&[]).map(|v| v.return_data)
.and_then(|r| Vec::<JsonMetadataDecodable>::decode(&mut &r.return_data[..])
.ok_or("JSON Metadata decoding failed".into()))
.and_then(|metadata| {
let mut json = metadata.into_iter().enumerate().fold(String::from("{"),
|mut json, (i, m)| {
if i > 0 {
json.push_str(",");
}
let (mtype, val) = m.into_json_string();
json.push_str(&format!(r#" "{}": {}"#, mtype, val));
json
}
);
json.push_str(" }");
Ok(json)
})
} }
/// Reads storage value at a given block + key, returning read proof. /// Reads storage value at a given block + key, returning read proof.
@@ -772,32 +754,4 @@ mod tests {
assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap()); assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap());
assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1) assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1)
} }
#[test]
fn json_metadata() {
let client = test_client::new();
let mut builder = client.new_block().unwrap();
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
amount: 42,
nonce: 0,
}).unwrap();
assert!(builder.push_transfer(Transfer {
from: Keyring::Eve.to_raw_public().into(),
to: Keyring::Alice.to_raw_public().into(),
amount: 42,
nonce: 0,
}).is_err());
client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
assert_eq!(
client.json_metadata(&BlockId::Number(1)).unwrap(),
r#"{ "events": { "name": "Test", "events": { "event": hallo } } }"#
);
}
} }
-1
View File
@@ -21,7 +21,6 @@
extern crate substrate_bft as bft; extern crate substrate_bft as bft;
extern crate parity_codec as codec; extern crate parity_codec as codec;
extern crate substrate_metadata;
extern crate substrate_primitives as primitives; extern crate substrate_primitives as primitives;
extern crate sr_io as runtime_io; extern crate sr_io as runtime_io;
extern crate sr_primitives as runtime_primitives; extern crate sr_primitives as runtime_primitives;
-13
View File
@@ -1,13 +0,0 @@
[package]
name = "substrate-metadata"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
parity-codec = { version = "1.1", default_features = false }
[features]
default = ["std"]
std = [
"parity-codec/std"
]
-190
View File
@@ -1,190 +0,0 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Decodable variant of the JsonMetadata.
//!
//! This really doesn't belong here, but is necessary for the moment. In the future
//! it should be removed entirely to an external module for shimming on to the
//! codec-encoded metadata.
#![cfg_attr(not(feature = "std"), no_std)]
extern crate parity_codec as codec;
use codec::{Encode, Output};
#[cfg(feature = "std")]
use codec::{Decode, Input};
/// The metadata of a runtime encoded as JSON.
#[derive(Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum JsonMetadata {
Events { name: &'static str, events: &'static [(&'static str, fn() -> &'static str)] },
Module { module: &'static str, prefix: &'static str },
ModuleWithStorage { module: &'static str, prefix: &'static str, storage: &'static str }
}
impl Encode for JsonMetadata {
fn encode_to<W: Output>(&self, dest: &mut W) {
match self {
JsonMetadata::Events { name, events } => {
0i8.encode_to(dest);
name.encode_to(dest);
events.iter().fold(0u32, |count, _| count + 1).encode_to(dest);
events
.iter()
.map(|(module, data)| (module, data()))
.for_each(|val| val.encode_to(dest));
},
JsonMetadata::Module { module, prefix } => {
1i8.encode_to(dest);
prefix.encode_to(dest);
module.encode_to(dest);
},
JsonMetadata::ModuleWithStorage { module, prefix, storage } => {
2i8.encode_to(dest);
prefix.encode_to(dest);
module.encode_to(dest);
storage.encode_to(dest);
}
}
}
}
impl PartialEq<JsonMetadata> for JsonMetadata {
fn eq(&self, other: &JsonMetadata) -> bool {
match (self, other) {
(
JsonMetadata::Events { name: lname, events: left },
JsonMetadata::Events { name: rname, events: right }
) => {
lname == rname && left.iter().zip(right.iter()).fold(true, |res, (l, r)| {
res && l.0 == r.0 && l.1() == r.1()
})
},
(
JsonMetadata::Module { prefix: lpre, module: lmod },
JsonMetadata::Module { prefix: rpre, module: rmod }
) => {
lpre == rpre && lmod == rmod
},
(
JsonMetadata::ModuleWithStorage { prefix: lpre, module: lmod, storage: lstore },
JsonMetadata::ModuleWithStorage { prefix: rpre, module: rmod, storage: rstore }
) => {
lpre == rpre && lmod == rmod && lstore == rstore
},
_ => false,
}
}
}
/// Utility struct for making `JsonMetadata` decodeable.
#[derive(Eq, PartialEq, Debug)]
#[cfg(feature = "std")]
pub enum JsonMetadataDecodable {
Events { name: String, events: Vec<(String, String)> },
Module { module: String, prefix: String },
ModuleWithStorage { module: String, prefix: String, storage: String }
}
#[cfg(feature = "std")]
impl JsonMetadataDecodable {
/// Returns the instance as JSON string.
/// The first value of the tuple is the name of the metadata type and the second in the JSON string.
pub fn into_json_string(self) -> (&'static str, String) {
match self {
JsonMetadataDecodable::Events { name, events } => {
(
"events",
format!(
r#"{{ "name": "{}", "events": {{ {} }} }}"#, name,
events.iter().enumerate()
.fold(String::from(""), |mut json, (i, (name, data))| {
if i > 0 {
json.push_str(", ");
}
json.push_str(&format!(r#""{}": {}"#, name, data));
json
})
)
)
},
JsonMetadataDecodable::Module { prefix, module } => {
("module", format!(r#"{{ "prefix": "{}", "module": {} }}"#, prefix, module))
},
JsonMetadataDecodable::ModuleWithStorage { prefix, module, storage } => {
(
"moduleWithStorage",
format!(
r#"{{ "prefix": "{}", "module": {}, "storage": {} }}"#,
prefix, module, storage
)
)
}
}
}
}
#[cfg(feature = "std")]
impl Decode for JsonMetadataDecodable {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
i8::decode(input).and_then(|variant| {
match variant {
0 => String::decode(input)
.and_then(|name| Vec::<(String, String)>::decode(input).map(|events| (name, events)))
.and_then(|(name, events)| Some(JsonMetadataDecodable::Events { name, events })),
1 => String::decode(input)
.and_then(|prefix| String::decode(input).map(|v| (prefix, v)))
.and_then(|(prefix, module)| Some(JsonMetadataDecodable::Module { prefix, module })),
2 => String::decode(input)
.and_then(|prefix| String::decode(input).map(|v| (prefix, v)))
.and_then(|(prefix, module)| String::decode(input).map(|v| (prefix, module, v)))
.and_then(|(prefix, module, storage)| Some(JsonMetadataDecodable::ModuleWithStorage { prefix, module, storage })),
_ => None,
}
})
}
}
#[cfg(feature = "std")]
impl PartialEq<JsonMetadata> for JsonMetadataDecodable {
fn eq(&self, other: &JsonMetadata) -> bool {
match (self, other) {
(
JsonMetadataDecodable::Events { name: lname, events: left },
JsonMetadata::Events { name: rname, events: right }
) => {
lname == rname && left.iter().zip(right.iter()).fold(true, |res, (l, r)| {
res && l.0 == r.0 && l.1 == r.1()
})
},
(
JsonMetadataDecodable::Module { prefix: lpre, module: lmod },
JsonMetadata::Module { prefix: rpre, module: rmod }
) => {
lpre == rpre && lmod == rmod
},
(
JsonMetadataDecodable::ModuleWithStorage { prefix: lpre, module: lmod, storage: lstore },
JsonMetadata::ModuleWithStorage { prefix: rpre, module: rmod, storage: rstore }
) => {
lpre == rpre && lmod == rmod && lstore == rstore
},
_ => false,
}
}
}
+2 -2
View File
@@ -145,8 +145,8 @@ impl<B, E, Block> StateApi<Block::Hash> for State<B, E, Block> where
fn metadata(&self, block: Trailing<Block::Hash>) -> Result<serde_json::Value> { fn metadata(&self, block: Trailing<Block::Hash>) -> Result<serde_json::Value> {
let block = self.unwrap_or_best(block)?; let block = self.unwrap_or_best(block)?;
let metadata = self.client.json_metadata(&BlockId::Hash(block))?; let metadata = self.client.metadata(&BlockId::Hash(block))?;
serde_json::from_str(&metadata).map_err(Into::into) serde_json::to_value(metadata).map_err(Into::into)
} }
fn query_storage(&self, keys: Vec<StorageKey>, from: Block::Hash, to: Trailing<Block::Hash>) -> Result<Vec<StorageChangeSet<Block::Hash>>> { fn query_storage(&self, keys: Vec<StorageKey>, from: Block::Hash, to: Trailing<Block::Hash>) -> Result<Vec<StorageChangeSet<Block::Hash>>> {
-11
View File
@@ -133,21 +133,10 @@ pub fn run_tests(mut input: &[u8]) -> Vec<u8> {
[stxs.len() as u8].encode() [stxs.len() as u8].encode()
} }
fn test_event_json() -> &'static str {
"hallo"
}
pub mod api { pub mod api {
use system; use system;
impl_stubs!( impl_stubs!(
version => |()| super::version(), version => |()| super::version(),
json_metadata => |()| {
let mut vec = ::runtime_support::metadata::Vec::new();
vec.push(::runtime_support::metadata::JsonMetadata::Events {
name: "Test", events: &[ ("event", super::test_event_json) ]
});
vec
},
authorities => |()| system::authorities(), authorities => |()| system::authorities(),
initialise_block => |header| system::initialise_block(header), initialise_block => |header| system::initialise_block(header),
execute_block => |block| system::execute_block(block), execute_block => |block| system::execute_block(block),
+3
View File
@@ -588,6 +588,9 @@ name = "substrate-metadata"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
+1 -1
View File
@@ -232,7 +232,7 @@ pub type Executive = executive::Executive<Runtime, Block, Balances, Balances, Al
pub mod api { pub mod api {
impl_stubs!( impl_stubs!(
version => |()| super::VERSION, version => |()| super::VERSION,
json_metadata => |()| super::Runtime::json_metadata(), metadata => |()| super::Runtime::metadata(),
authorities => |()| super::Consensus::authorities(), authorities => |()| super::Consensus::authorities(),
initialise_block => |header| super::Executive::initialise_block(&header), initialise_block => |header| super::Executive::initialise_block(&header),
apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic), apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic),
+3
View File
@@ -879,6 +879,9 @@ name = "substrate-metadata"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "substrate-metadata"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
parity-codec = { version = "1.1", default_features = false }
parity-codec-derive = { version = "^1.0", default_features = false }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
[features]
default = ["std"]
std = [
"parity-codec/std",
"parity-codec-derive/std",
"serde",
"serde_derive"
]
+279
View File
@@ -0,0 +1,279 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Decodable variant of the RuntimeMetadata.
//!
//! This really doesn't belong here, but is necessary for the moment. In the future
//! it should be removed entirely to an external module for shimming on to the
//! codec-encoded metadata.
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[macro_use]
extern crate parity_codec_derive;
extern crate parity_codec as codec;
#[cfg(feature = "std")]
extern crate serde;
#[cfg(feature = "std")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "std")]
pub mod alloc {
pub use std::vec;
}
use codec::{Encode, Output};
#[cfg(feature = "std")]
use codec::{Decode, Input};
// Make Vec available on `std` and `no_std`
use alloc::vec::Vec;
#[cfg(feature = "std")]
type StringBuf = String;
/// On `no_std` we do not support `Decode` and thus `StringBuf` is just `&'static str`.
/// So, if someone tries to decode this stuff on `no_std`, they will get a compilation error.
#[cfg(not(feature = "std"))]
type StringBuf = &'static str;
/// A type that decodes to a different type than it encodes.
/// The user needs to make sure that both types use the same encoding.
///
/// For example a `&'static [ &'static str ]` can be decoded to a `Vec<String>`.
#[derive(Clone)]
pub enum DecodeDifferent<B, O> where B: 'static, O: 'static {
Encode(B),
Decoded(O),
}
impl<B, O> Encode for DecodeDifferent<B, O> where B: Encode + 'static, O: Encode + 'static {
fn encode_to<W: Output>(&self, dest: &mut W) {
match self {
DecodeDifferent::Encode(b) => b.encode_to(dest),
DecodeDifferent::Decoded(o) => o.encode_to(dest),
}
}
}
#[cfg(feature = "std")]
impl<B, O> Decode for DecodeDifferent<B, O> where B: 'static, O: Decode + 'static {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
<O>::decode(input).and_then(|val| {
Some(DecodeDifferent::Decoded(val))
})
}
}
impl<B, O> PartialEq for DecodeDifferent<B, O>
where
B: Encode + Eq + PartialEq + 'static,
O: Encode + Eq + PartialEq + 'static,
{
fn eq(&self, other: &Self) -> bool {
self.encode() == other.encode()
}
}
impl<B, O> Eq for DecodeDifferent<B, O>
where B: Encode + Eq + PartialEq + 'static, O: Encode + Eq + PartialEq + 'static
{}
#[cfg(feature = "std")]
impl<B, O> std::fmt::Debug for DecodeDifferent<B, O>
where
B: std::fmt::Debug + Eq + 'static,
O: std::fmt::Debug + Eq + 'static,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DecodeDifferent::Encode(b) => b.fmt(f),
DecodeDifferent::Decoded(o) => o.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl<B, O> serde::Serialize for DecodeDifferent<B, O>
where
B: serde::Serialize + 'static,
O: serde::Serialize + 'static,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
DecodeDifferent::Encode(b) => b.serialize(serializer),
DecodeDifferent::Decoded(o) => o.serialize(serializer),
}
}
}
type DecodeDifferentArray<B, O=B> = DecodeDifferent<&'static [B], Vec<O>>;
#[cfg(feature = "std")]
type DecodeDifferentStr = DecodeDifferent<&'static str, StringBuf>;
#[cfg(not(feature = "std"))]
type DecodeDifferentStr = DecodeDifferent<&'static str, StringBuf>;
/// All the metadata about a module.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct ModuleMetadata {
pub name: DecodeDifferentStr,
pub call: CallMetadata,
}
/// All the metadata about a call.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct CallMetadata {
pub name: DecodeDifferentStr,
pub functions: DecodeDifferentArray<FunctionMetadata>,
}
/// All the metadata about a function.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct FunctionMetadata {
pub id: u16,
pub name: DecodeDifferentStr,
pub arguments: DecodeDifferentArray<FunctionArgumentMetadata>,
pub documentation: DecodeDifferentArray<&'static str, StringBuf>,
}
/// All the metadata about a function argument.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct FunctionArgumentMetadata {
pub name: DecodeDifferentStr,
pub ty: DecodeDifferentStr,
}
/// Newtype wrapper for support encoding functions (actual the result of the function).
#[derive(Clone, Eq)]
pub struct FnEncode<E>(pub fn() -> E) where E: Encode + 'static;
impl<E: Encode> Encode for FnEncode<E> {
fn encode_to<W: Output>(&self, dest: &mut W) {
self.0().encode_to(dest);
}
}
impl<E: Encode + PartialEq> PartialEq for FnEncode<E> {
fn eq(&self, other: &Self) -> bool {
self.0().eq(&other.0())
}
}
#[cfg(feature = "std")]
impl<E: Encode + ::std::fmt::Debug> std::fmt::Debug for FnEncode<E> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.0().fmt(f)
}
}
#[cfg(feature = "std")]
impl<E: Encode + serde::Serialize> serde::Serialize for FnEncode<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0().serialize(serializer)
}
}
/// All the metadata about an outer event.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct OuterEventMetadata {
pub name: DecodeDifferentStr,
pub events: DecodeDifferentArray<
(&'static str, FnEncode<&'static [EventMetadata]>),
(StringBuf, Vec<EventMetadata>)
>,
}
/// All the metadata about a event.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct EventMetadata {
pub name: DecodeDifferentStr,
pub arguments: DecodeDifferentArray<&'static str, StringBuf>,
pub documentation: DecodeDifferentArray<&'static str, StringBuf>,
}
/// All the metadata about a storage.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct StorageMetadata {
pub prefix: DecodeDifferentStr,
pub functions: DecodeDifferentArray<StorageFunctionMetadata>,
}
/// All the metadata about a storage function.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct StorageFunctionMetadata {
pub name: DecodeDifferentStr,
pub modifier: StorageFunctionModifier,
pub ty: StorageFunctionType,
pub documentation: DecodeDifferentArray<&'static str, StringBuf>,
}
/// A storage function type.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub enum StorageFunctionType {
Plain(DecodeDifferentStr),
Map {
key: DecodeDifferentStr,
value: DecodeDifferentStr,
}
}
/// A storage function modifier.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub enum StorageFunctionModifier {
None,
Default,
Required,
}
/// All metadata about an runtime module.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct RuntimeModuleMetadata {
pub prefix: DecodeDifferentStr,
pub module: DecodeDifferent<FnEncode<ModuleMetadata>, ModuleMetadata>,
pub storage: Option<DecodeDifferent<FnEncode<StorageMetadata>, StorageMetadata>>,
}
/// The metadata of a runtime.
#[derive(Eq, Encode, PartialEq)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct RuntimeMetadata {
pub outer_event: OuterEventMetadata,
pub modules: DecodeDifferentArray<RuntimeModuleMetadata>,
}
+2 -3
View File
@@ -9,15 +9,14 @@ serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
parity-codec = { version = "1.1", default_features = false } parity-codec = { version = "1.1", default_features = false }
substrate-primitives = { path = "../../core/primitives", 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-std = { path = "../../core/sr-std", default_features = false }
sr-io = { path = "../../core/sr-io", default_features = false } sr-io = { path = "../../core/sr-io", default_features = false }
mashup = "0.1.7" mashup = "0.1.7"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.5.1" pretty_assertions = "0.5.1"
serde_json = { version = "1.0" } parity-codec-derive = { version = "1.0" }
parity-codec-derive = { version = "~1.0" }
[features] [features]
default = ["std"] default = ["std"]
+141 -94
View File
@@ -23,6 +23,10 @@ pub use rstd::result;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use serde; use serde;
pub use codec::{Codec, Decode, Encode, Input, Output}; pub use codec::{Codec, Decode, Encode, Input, Output};
pub use substrate_metadata::{
ModuleMetadata, FunctionMetadata, DecodeDifferent,
CallMetadata, FunctionArgumentMetadata
};
pub type Result = result::Result<(), &'static str>; pub type Result = result::Result<(), &'static str>;
@@ -306,7 +310,7 @@ macro_rules! decl_module {
d.dispatch(origin) d.dispatch(origin)
} }
} }
__dispatch_impl_json_metadata! { __dispatch_impl_metadata! {
$mod_type $trait_instance $trait_name $call_type $origin_type $mod_type $trait_instance $trait_name $call_type $origin_type
{$( $(#[doc = $doc_attr])* fn $fn_name($from $(, $param_name : $param )*) -> $result; )*} {$( $(#[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. /// Implement the `json_metadata` function.
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __dispatch_impl_json_metadata { macro_rules! __dispatch_impl_metadata {
( (
$mod_type:ident $trait_instance:ident $trait_name:ident $mod_type:ident $trait_instance:ident $trait_name:ident
$($rest:tt)* $($rest:tt)*
) => { ) => {
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> { impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
pub fn json_metadata() -> &'static str { pub fn metadata() -> $crate::dispatch::ModuleMetadata {
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "call": "#, $crate::dispatch::ModuleMetadata {
__call_to_json!($($rest)*), " }") 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 ",". /// Convert the list of calls into their JSON representation, joined by ",".
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __call_to_json { macro_rules! __call_to_metadata {
( (
$call_type:ident $origin_type:ty $call_type:ident $origin_type:ty
{$( {$(
@@ -490,111 +496,111 @@ macro_rules! __call_to_json {
) -> $result:ty; ) -> $result:ty;
)*} )*}
) => { ) => {
concat!( $crate::dispatch::CallMetadata {
r#"{ "name": ""#, stringify!($call_type), name: $crate::dispatch::DecodeDifferent::Encode(stringify!($call_type)),
r#"", "functions": {"#, functions: __functions_to_metadata!(0; $origin_type;; $(
__functions_to_json!(""; 0; $origin_type; $(
fn $fn_name($from $(, $param_name: $param )* ) -> $result; 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] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __functions_to_json { macro_rules! __functions_to_metadata{
// ROOT // ROOT
( (
$prefix_str:tt;
$fn_id:expr; $fn_id:expr;
$origin_type:ty; $origin_type:ty;
$( $function_metadata:expr ),*;
fn $fn_name:ident(root fn $fn_name:ident(root
$( $(
, $param_name:ident : $param:ty , $param_name:ident : $param:ty
)* )*
) -> $result:ty; ) -> $result:ty;
$fn_doc:expr; $( $fn_doc:expr ),*;
$($rest:tt)* $( $rest:tt )*
) => { ) => {
concat!($prefix_str, " ", __functions_to_metadata!(
__function_to_json!( $fn_id + 1; $origin_type;
fn $fn_name( $( $function_metadata, )* __function_to_metadata!(
$( $param_name : $param ),* fn $fn_name($( $param_name : $param ),*) -> $result; $( $fn_doc ),*; $fn_id;
) -> $result; );
$fn_doc; $($rest)*
$fn_id; )
), __functions_to_json!(","; $fn_id + 1; $origin_type; $($rest)*)
)
}; };
// NON ROOT // NON ROOT
( (
$prefix_str:tt;
$fn_id:expr; $fn_id:expr;
$origin_type:ty; $origin_type:ty;
$( $function_metadata:expr ),*;
fn $fn_name:ident(origin fn $fn_name:ident(origin
$( $(
, $param_name:ident : $param:ty , $param_name:ident : $param:ty
)* )*
) -> $result:ty; ) -> $result:ty;
$fn_doc:expr; $( $fn_doc:expr ),*;
$($rest:tt)* $($rest:tt)*
) => { ) => {
concat!($prefix_str, " ", __functions_to_metadata!(
__function_to_json!( $fn_id + 1; $origin_type;
fn $fn_name( $( $function_metadata, )* __function_to_metadata!(
origin: $origin_type fn $fn_name(
$(, $param_name : $param)* origin: $origin_type
) -> $result; $( ,$param_name : $param )*
$fn_doc; ) -> $result; $( $fn_doc ),*; $fn_id;
$fn_id; );
), __functions_to_json!(","; $fn_id + 1; $origin_type; $($rest)*) $($rest)*
) )
}; };
// BASE CASE // BASE CASE
( (
$prefix_str:tt;
$fn_id:expr; $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] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __function_to_json { macro_rules! __function_to_metadata {
( (
fn $fn_name:ident( fn $fn_name:ident(
$first_param_name:ident : $first_param:ty $(, $param_name:ident : $param:ty)* $($param_name:ident : $param:ty),*
) -> $result:ty; ) -> $result:ty;
$fn_doc:tt; $( $fn_doc:expr ),*;
$fn_id:expr; $fn_id:expr;
) => { ) => {
concat!( $crate::dispatch::FunctionMetadata {
r#"""#, stringify!($fn_id), r#"""#, id: $fn_id,
r#": { "name": ""#, stringify!($fn_name), name: $crate::dispatch::DecodeDifferent::Encode(stringify!($fn_name)),
r#"", "params": [ "#, arguments: $crate::dispatch::DecodeDifferent::Encode(&[
concat!(r#"{ "name": ""#, stringify!($first_param_name), r#"", "type": ""#, stringify!($first_param), r#"" }"# ),
$( $(
concat!(r#", { "name": ""#, stringify!($param_name), r#"", "type": ""#, stringify!($param), r#"" }"# ), $crate::dispatch::FunctionArgumentMetadata {
)* name: $crate::dispatch::DecodeDifferent::Encode(stringify!($param_name)),
r#" ], "description": ["#, $fn_doc, " ] }" ty: $crate::dispatch::DecodeDifferent::Encode(stringify!($param)),
) }
),*
]),
documentation: $crate::dispatch::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]),
}
}; };
( (
fn $fn_name:ident() -> $result:ty; fn $fn_name:ident() -> $result:ty;
$fn_doc:tt; $( $fn_doc:expr ),*;
$fn_id:expr; $fn_id:expr;
) => { ) => {
concat!( $crate::dispatch::FunctionMetadata {
r#"""#, stringify!($fn_id), r#"""#, id: $fn_id,
r#": { "name": ""#, stringify!($fn_name), name: $crate::dispatch::DecodeDifferent::Encode(stringify!($fn_name)),
r#"", "params": [ "#, arguments: $crate::dispatch::DecodeDifferent::Encode(&[]),
r#" ], "description": ["#, $fn_doc, " ] }" documentation: $crate::dispatch::DecodeDifferent::Encode(&[ $( $fn_doc ),* ]),
) }
}; };
} }
@@ -626,8 +632,6 @@ macro_rules! __function_doc_to_json {
#[allow(dead_code)] #[allow(dead_code)]
mod tests { mod tests {
use super::*; use super::*;
use serde;
use serde_json;
pub trait Trait { pub trait Trait {
type Origin; type Origin;
@@ -652,33 +656,78 @@ mod tests {
} }
} }
const EXPECTED_METADATA: &str = concat!( const EXPECTED_METADATA: ModuleMetadata = ModuleMetadata {
r#"{ "name": "Module", "call": "#, name: DecodeDifferent::Encode("Module"),
r#"{ "name": "Call", "functions": { "#, call: CallMetadata {
r#""0": { "name": "aux_0", "params": [ "#, name: DecodeDifferent::Encode("Call"),
r#"{ "name": "origin", "type": "T::Origin" }"#, functions: DecodeDifferent::Encode(&[
r#" ], "description": [ " Hi, this is a comment." ] }, "#, FunctionMetadata {
id: 0,
r#""0 + 1": { "name": "aux_1", "params": [ "#, name: DecodeDifferent::Encode("aux_0"),
r#"{ "name": "origin", "type": "T::Origin" }, "#, arguments: DecodeDifferent::Encode(&[
r#"{ "name": "data", "type": "i32" }"#, FunctionArgumentMetadata {
r#" ], "description": [ ] }, "#, name: DecodeDifferent::Encode("origin"),
ty: DecodeDifferent::Encode("T::Origin"),
r#""0 + 1 + 1": { "name": "aux_2", "params": [ "#, }
r#"{ "name": "origin", "type": "T::Origin" }, "#, ]),
r#"{ "name": "data", "type": "i32" }, "#, documentation: DecodeDifferent::Encode(&[
r#"{ "name": "data2", "type": "String" }"#, " Hi, this is a comment."
r#" ], "description": [ ] }, "#, ])
},
r#""0 + 1 + 1 + 1": { "name": "aux_3", "params": [ "#, FunctionMetadata {
r#" ], "description": [ ] }, "#, id: 1,
name: DecodeDifferent::Encode("aux_1"),
r#""0 + 1 + 1 + 1 + 1": { "name": "aux_4", "params": [ "#, arguments: DecodeDifferent::Encode(&[
r#"{ "name": "data", "type": "i32" }"#, FunctionArgumentMetadata {
r#" ], "description": [ ] }"#, name: DecodeDifferent::Encode("origin"),
r#" } }"#, ty: DecodeDifferent::Encode("T::Origin"),
r#" }"#, },
); 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> { impl<T: Trait> Module<T> {
fn aux_0(_: T::Origin) -> Result { fn aux_0(_: T::Origin) -> Result {
@@ -710,9 +759,7 @@ mod tests {
#[test] #[test]
fn module_json_metadata() { fn module_json_metadata() {
let metadata = Module::<TraitImpl>::json_metadata(); let metadata = Module::<TraitImpl>::metadata();
assert_eq!(EXPECTED_METADATA, 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 // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // 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. /// Implement the `Event` for a module.
/// ///
/// # Simple Event Example: /// # Simple Event Example:
@@ -125,8 +127,8 @@ macro_rules! decl_event {
} }
impl Event { impl Event {
#[allow(dead_code)] #[allow(dead_code)]
pub fn event_json_metadata() -> &'static str { pub fn metadata() -> &'static [ $crate::event::EventMetadata ] {
concat!("{", __events_to_json!(""; $( $events )* ), " }") __events_to_metadata!(; $( $events )* )
} }
} }
} }
@@ -226,8 +228,8 @@ macro_rules! __decl_generic_event {
} }
impl<$( $generic_param ),*> RawEvent<$( $generic_param ),*> { impl<$( $generic_param ),*> RawEvent<$( $generic_param ),*> {
#[allow(dead_code)] #[allow(dead_code)]
pub fn event_json_metadata() -> &'static str { pub fn metadata() -> &'static [$crate::event::EventMetadata] {
concat!("{", __events_to_json!(""; $( $events )* ), " }") __events_to_metadata!(; $( $events )* )
} }
} }
} }
@@ -235,36 +237,31 @@ macro_rules! __decl_generic_event {
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __events_to_json { macro_rules! __events_to_metadata {
( (
$prefix_str:expr; $( $metadata:expr ),*;
$( #[doc = $doc_attr:tt] )* $( #[doc = $doc_attr:tt] )*
$event:ident( $first_param:path $(, $param:path )* ), $event:ident $( ( $( $param:path ),* ) )*,
$( $rest:tt )* $( $rest:tt )*
) => { ) => {
concat!($prefix_str, " ", "\"", stringify!($event), r#"": { "params": [ ""#, __events_to_metadata!(
stringify!($first_param), "\"" $( $metadata, )*
$(, concat!(", \"", stringify!($param), "\"") )*, r#" ], "description": ["#, $crate::event::EventMetadata {
__function_doc_to_json!(""; $( $doc_attr )*), " ] }", name: $crate::event::DecodeDifferent::Encode(stringify!($event)),
__events_to_json!(","; $( $rest )*) arguments: $crate::event::DecodeDifferent::Encode(&[
$( $( stringify!($param) ),* )*
]),
documentation: $crate::event::DecodeDifferent::Encode(&[
$( $doc_attr ),*
]),
};
$( $rest )*
) )
}; };
( (
$prefix_str:expr; $( $metadata:expr ),*;
$( #[doc = $doc_attr:tt] )*
$event:ident,
$( $rest:tt )*
) => { ) => {
concat!($prefix_str, " ", "\"", stringify!($event), &[ $( $metadata ),* ]
r#"": { "params": null, "description": ["#,
__function_doc_to_json!(""; $( $doc_attr )*), " ] }",
__events_to_json!(","; $( $rest )*)
)
};
(
$prefix_str:expr;
) => {
""
} }
} }
@@ -408,20 +405,21 @@ macro_rules! __impl_outer_event_json_metadata {
) => { ) => {
impl $runtime { impl $runtime {
#[allow(dead_code)] #[allow(dead_code)]
pub fn outer_event_json_metadata() -> (&'static str, &'static [(&'static str, fn() -> &'static str)]) { pub fn outer_event_metadata() -> $crate::event::OuterEventMetadata {
static METADATA: &[(&str, fn() -> &'static str)] = &[ $crate::event::OuterEventMetadata {
("system", $system::Event::event_json_metadata) name: $crate::event::DecodeDifferent::Encode(stringify!($event_name)),
$( events: $crate::event::DecodeDifferent::Encode(&[
, ( ("system", $crate::event::FnEncode(system::Event::metadata))
stringify!($module_name), $(
$module_name::Event $( ::<$generic_param> )*::event_json_metadata , (
) stringify!($module_name),
)* $crate::event::FnEncode(
]; $module_name::Event $( ::<$generic_param> )* ::metadata
( )
stringify!($event_name), )
METADATA )*
) ])
}
} }
} }
} }
@@ -430,8 +428,7 @@ macro_rules! __impl_outer_event_json_metadata {
#[cfg(test)] #[cfg(test)]
#[allow(dead_code)] #[allow(dead_code)]
mod tests { mod tests {
use serde; use super::*;
use serde_json;
mod system { mod system {
pub trait Trait { pub trait Trait {
@@ -567,46 +564,64 @@ mod tests {
type Origin = u32; type Origin = u32;
} }
const EXPECTED_METADATA: (&str, &[(&str, &str)]) = ( const EXPECTED_METADATA: OuterEventMetadata = OuterEventMetadata {
"TestEvent", &[ name: DecodeDifferent::Encode("TestEvent"),
("system", r#"{ "SystemEvent": { "params": null, "description": [ ] } }"#), events: DecodeDifferent::Encode(&[
("event_module", (
concat!( "system",
"{", FnEncode(|| &[
r#" "TestEvent": { "params": [ "Balance", "Origin" ], "description": [ " Hi, I am a comment." ] },"#, EventMetadata {
r#" "EventWithoutParams": { "params": null, "description": [ " Dog" ] }"#, name: DecodeDifferent::Encode("SystemEvent"),
" }" arguments: DecodeDifferent::Encode(&[]),
) documentation: DecodeDifferent::Encode(&[]),
}
])
), ),
("event_module2", (
concat!( "event_module",
"{", FnEncode(|| &[
r#" "TestEvent": { "params": [ "BalanceRenamed" ], "description": [ ] },"#, EventMetadata {
r#" "TestOrigin": { "params": [ "OriginRenamed" ], "description": [ ] }"#, 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!( "event_module2",
"{", FnEncode(|| &[
r#" "HiEvent": { "params": null, "description": [ ] }"#, 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] #[test]
fn outer_event_json_metadata() { fn outer_event_metadata() {
let metadata = TestRuntime::outer_event_json_metadata(); assert_eq!(EXPECTED_METADATA, TestRuntime::outer_event_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()));
}
} }
} }
+1 -3
View File
@@ -41,8 +41,6 @@ extern crate pretty_assertions;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
#[cfg(test)] #[cfg(test)]
extern crate serde_json;
#[cfg(test)]
#[macro_use] #[macro_use]
extern crate parity_codec_derive; extern crate parity_codec_derive;
@@ -62,7 +60,7 @@ pub mod dispatch;
pub mod storage; pub mod storage;
mod hashable; mod hashable;
#[macro_use] #[macro_use]
mod event; pub mod event;
#[macro_use] #[macro_use]
pub mod metadata; pub mod metadata;
#[macro_use] #[macro_use]
+129 -120
View File
@@ -14,38 +14,30 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use alloc; pub use substrate_metadata::{
pub use substrate_metadata::JsonMetadata; DecodeDifferent, FnEncode, RuntimeMetadata, RuntimeModuleMetadata
};
/// Make Box available on `std` and `no_std`. /// Implements the metadata support for the given runtime and all its modules.
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.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```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. /// In this example, just `MODULE3` implements the `Storage` trait.
#[macro_export] #[macro_export]
macro_rules! impl_json_metadata { macro_rules! impl_runtime_metadata {
( (
for $runtime:ident with modules for $runtime:ident with modules
$( $rest:tt )* $( $rest:tt )*
) => { ) => {
impl $runtime { impl $runtime {
pub fn json_metadata() -> $crate::metadata::Vec<$crate::metadata::JsonMetadata> { pub fn metadata() -> $crate::metadata::RuntimeMetadata {
let events = Self::outer_event_json_metadata(); $crate::metadata::RuntimeMetadata {
__impl_json_metadata!($runtime; outer_event: Self::outer_event_metadata(),
$crate::metadata::JsonMetadata::Events { modules: __runtime_modules_to_metadata!($runtime;; $( $rest )*),
name: events.0, }
events: events.1,
};
$( $rest )*
)
} }
} }
} }
@@ -53,66 +45,50 @@ macro_rules! impl_json_metadata {
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __impl_json_metadata { macro_rules! __runtime_modules_to_metadata {
( (
$runtime: ident; $runtime: ident;
$( $metadata:expr ),*; $( $metadata:expr ),*;
$mod:ident::$module:ident, $mod:ident::$module:ident,
$( $rest:tt )* $( $rest:tt )*
) => { ) => {
__impl_json_metadata!( __runtime_modules_to_metadata!(
$runtime; $runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::Module { $( $metadata, )* $crate::metadata::RuntimeModuleMetadata {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod) prefix: $crate::metadata::DecodeDifferent::Encode(stringify!($mod)),
module: $crate::metadata::DecodeDifferent::Encode(
$crate::metadata::FnEncode($mod::$module::<$runtime>::metadata)
),
storage: None,
}; };
$( $rest )* $( $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; $runtime: ident;
$( $metadata:expr ),*; $( $metadata:expr ),*;
$mod:ident::$module:ident with Storage, $mod:ident::$module:ident with Storage,
$( $rest:tt )* $( $rest:tt )*
) => { ) => {
__impl_json_metadata!( __runtime_modules_to_metadata!(
$runtime; $runtime;
$( $metadata, )* $crate::metadata::JsonMetadata::ModuleWithStorage { $( $metadata, )* $crate::metadata::RuntimeModuleMetadata {
module: $mod::$module::<$runtime>::json_metadata(), prefix: stringify!($mod), prefix: $crate::metadata::DecodeDifferent::Encode(stringify!($mod)),
storage: $mod::$module::<$runtime>::store_json_metadata() 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 )* $( $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; $runtime:ident;
$( $metadata:expr ),*; $( $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)] #[allow(dead_code)]
mod tests { mod tests {
use super::*; use super::*;
use serde; use substrate_metadata::{
use serde_json; EventMetadata, OuterEventMetadata, RuntimeModuleMetadata, CallMetadata, ModuleMetadata,
use substrate_metadata::JsonMetadataDecodable; StorageFunctionModifier, StorageFunctionType, FunctionMetadata, FunctionArgumentMetadata,
StorageMetadata, StorageFunctionMetadata,
};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
mod system { mod system {
@@ -219,79 +197,110 @@ mod tests {
type Origin = u32; type Origin = u32;
} }
fn system_event_json() -> &'static str { impl_runtime_metadata!(
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!(
for TestRuntime with modules for TestRuntime with modules
event_module::Module, event_module::Module,
event_module2::ModuleWithStorage with Storage event_module2::ModuleWithStorage with Storage,
); );
const EXPECTED_METADATA: &[JsonMetadata] = &[ const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata {
JsonMetadata::Events { outer_event: OuterEventMetadata {
name: "TestEvent", name: DecodeDifferent::Encode("TestEvent"),
events: &[ events: DecodeDifferent::Encode(&[
("system", system_event_json), (
("event_module", event_module_event_json), "system",
("event_module2", event_module2_event_json), 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 { modules: DecodeDifferent::Encode(&[
module: concat!( RuntimeModuleMetadata {
r#"{ "name": "Module", "call": "#, prefix: DecodeDifferent::Encode("event_module"),
r#"{ "name": "Call", "functions": "#, module: DecodeDifferent::Encode(FnEncode(||
r#"{ "0": { "name": "aux_0", "params": [ "#, ModuleMetadata {
r#"{ "name": "origin", "type": "T::Origin" } ], "#, name: DecodeDifferent::Encode("Module"),
r#""description": [ ] } } } }"# call: CallMetadata {
), name: DecodeDifferent::Encode("Call"),
prefix: "event_module" functions: DecodeDifferent::Encode(&[
}, FunctionMetadata {
JsonMetadata::ModuleWithStorage { id: 0,
module: r#"{ "name": "ModuleWithStorage", "call": { "name": "Call", "functions": { } } }"#, name: DecodeDifferent::Encode("aux_0"),
prefix: "event_module2", arguments: DecodeDifferent::Encode(&[
storage: concat!( FunctionArgumentMetadata {
r#"{ "prefix": "TestStorage", "items": { "#, name: DecodeDifferent::Encode("origin"),
r#""StorageMethod": { "description": [ ], "modifier": null, "type": "u32" }"#, ty: DecodeDifferent::Encode("T::Origin"),
r#" } }"# }
) ]),
} 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] #[test]
fn runtime_json_metadata() { fn runtime_metadata() {
let metadata = TestRuntime::json_metadata(); let metadata = TestRuntime::metadata();
assert_eq!(EXPECTED_METADATA, &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_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[..]); assert_eq!(metadata, metadata_decoded.unwrap());
}
#[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));
}
} }
} }
+10 -10
View File
@@ -275,7 +275,7 @@ macro_rules! construct_runtime {
$name: $module::{ $( $modules $( <$modules_generic> )* ),* } $name: $module::{ $( $modules $( <$modules_generic> )* ),* }
),*; ),*;
); );
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
; ;
; ;
@@ -664,7 +664,7 @@ macro_rules! __decl_outer_dispatch {
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __decl_json_metadata { macro_rules! __decl_runtime_metadata {
( (
$runtime:ident; $runtime:ident;
; ;
@@ -676,7 +676,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
$module { Module, }; $module { Module, };
$( $parsed_modules { Module $( with $parsed_storage )* } ),*; $( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -699,7 +699,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
; ;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module with Storage }; $( $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> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
$module { , Storage }; $module { , Storage };
$( $parsed_modules { Module $( with $parsed_storage )* } ),*; $( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -744,7 +744,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
; ;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module with Storage }; $( $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> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
$( $current_module { $( $current_module_storage )* } )*; $( $current_module { $( $current_module_storage )* } )*;
$( $parsed_modules { Module $( with $parsed_storage )* } ),*; $( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -787,7 +787,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
; ;
$( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module }; $( $parsed_modules { Module $( with $parsed_storage )* }, )* $module { Module };
@@ -807,7 +807,7 @@ macro_rules! __decl_json_metadata {
$( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),* $( $rest_modules:ident $( <$rest_modules_generic:ident> )* ),*
})*; })*;
) => { ) => {
__decl_json_metadata!( __decl_runtime_metadata!(
$runtime; $runtime;
; ;
$( $parsed_modules { Module $( with $parsed_storage )* } ),*; $( $parsed_modules { Module $( with $parsed_storage )* } ),*;
@@ -824,7 +824,7 @@ macro_rules! __decl_json_metadata {
$( $parsed_modules:ident { Module $( with $parsed_storage:ident )* } ),*; $( $parsed_modules:ident { Module $( with $parsed_storage:ident )* } ),*;
; ;
) => { ) => {
impl_json_metadata!( impl_runtime_metadata!(
for $runtime with modules for $runtime with modules
$( $parsed_modules::Module $(with $parsed_storage)*, )* $( $parsed_modules::Module $(with $parsed_storage)*, )*
); );
+448 -264
View File
@@ -53,6 +53,11 @@ pub use rstd::borrow::Borrow;
#[doc(hidden)] #[doc(hidden)]
pub use rstd::marker::PhantomData; pub use rstd::marker::PhantomData;
pub use substrate_metadata::{
DecodeDifferent, StorageMetadata, StorageFunctionMetadata,
StorageFunctionType, StorageFunctionModifier
};
/// Abstraction around storage. /// Abstraction around storage.
pub trait Storage { pub trait Storage {
/// true if the key exists in storage. /// true if the key exists in storage.
@@ -530,7 +535,7 @@ macro_rules! decl_storage {
} }
impl<$traitinstance: $traittype> $modulename<$traitinstance> { impl<$traitinstance: $traittype> $modulename<$traitinstance> {
__impl_store_fns!($traitinstance $($t)*); __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] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __impl_store_json_metadata { macro_rules! __impl_store_metadata {
( (
$cratename:ident; $cratename:ident;
$($rest:tt)* $($rest:tt)*
) => { ) => {
pub fn store_json_metadata() -> &'static str { pub fn store_metadata() -> $crate::storage::generator::StorageMetadata {
concat!(r#"{ "prefix": ""#, stringify!($cratename), r#"", "items": {"#, $crate::storage::generator::StorageMetadata {
__store_functions_to_json!(""; $($rest)*), " } }") prefix: $crate::storage::generator::DecodeDifferent::Encode(stringify!($cratename)),
functions: __store_functions_to_metadata!(; $( $rest )* ),
}
} }
} }
} }
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! __store_functions_to_json { macro_rules! __store_functions_to_metadata {
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident : default $ty:ty;
default $ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident : default $ty:ty;
default $ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident : required $ty:ty;
required $ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident : required $ty:ty;
required $ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
// simple values // simple values
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident : $ty:ty;
$ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident : $ty:ty;
$ty:ty; $($t:tt)* $($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) : $name:ident get($getfn:ident) :
default $ty:ty; $($t:tt)* default $ty:ty;
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) :
default $ty:ty; $($t:tt)* default $ty:ty;
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) : $name:ident get($getfn:ident) :
required $ty:ty; $($t:tt)* required $ty:ty;
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) :
required $ty:ty; $($t:tt)* required $ty:ty;
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) : $name:ident get($getfn:ident) : $ty:ty;
$ty:ty; $($t:tt)* $( $t:tt )*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) : $ty:ty;
$ty:ty; $($t:tt)* $( $t:tt )*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
// maps // maps
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident :
default map [$kty:ty => $ty:ty]; $($t:tt)* default map [$kty:ty => $ty:ty];
$( $t:tt )*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident :
default map [$kty:ty => $ty:ty]; $($t:tt)* default map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident :
required map [$kty:ty => $ty:ty]; $($t:tt)* required map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident :
required map [$kty:ty => $ty:ty]; $($t:tt)* required map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident : $name:ident :
map [$kty:ty => $ty:ty]; $($t:tt)* map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident : pub $name:ident :
map [$kty:ty => $ty:ty]; $($t:tt)* map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $name:ident get($getfn:ident) : $(#[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_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) :
default map [$kty:ty => $ty:ty]; $($t:tt)* default map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), default $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), default
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $name:ident get($getfn:ident) : $(#[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_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
), );
__store_functions_to_json!(","; $($t)*) $( $t )*
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) :
required map [$kty:ty => $ty:ty]; $($t:tt)* required map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty), required $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty), required
), ); $( $t )*
__store_functions_to_json!(","; $($t)*)
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
$name:ident get($getfn:ident) : $name:ident get($getfn:ident) :
map [$kty:ty => $ty:ty]; $($t:tt)* map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
), ); $( $t )*
__store_functions_to_json!(","; $($t)*)
) )
}; };
( (
$prefix_str:tt; $( $metadata:expr ),*;
$(#[doc = $doc_attr:tt])* $(#[doc = $doc_attr:tt])*
pub $name:ident get($getfn:ident) : pub $name:ident get($getfn:ident) :
map [$kty:ty => $ty:ty]; $($t:tt)* map [$kty:ty => $ty:ty];
$($t:tt)*
) => { ) => {
concat!( __store_functions_to_metadata!(
__store_function_to_json!($prefix_str, $( $metadata, )*
__function_doc_to_json!(""; $($doc_attr)*), __store_function_to_metadata!(
$name, __store_type_to_json!($kty, $ty) $( $doc_attr ),*; $name, __store_type_to_metadata!($kty, $ty)
), ); $( $t )*
__store_functions_to_json!(","; $($t)*)
) )
}; };
($prefix_str:tt;) => { "" } (
} $( $metadata:expr ),*;
) => {
#[macro_export] $crate::storage::generator::DecodeDifferent::Encode(&[
#[doc(hidden)] $( $metadata ),*
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#" }"#
)
} }
} }
#[macro_export] #[macro_export]
#[doc(hidden)] #[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) => { ($name:ty) => {
concat!("\"", stringify!($name), "\"") $crate::storage::generator::StorageFunctionType::Plain(
$crate::storage::generator::DecodeDifferent::Encode(stringify!($name)),
)
}; };
($key: ty, $value:ty) => { ($key: ty, $value:ty) => {
concat!(r#"{ "key": ""#, stringify!($key), r#"", "value": ""#, $crate::storage::generator::StorageFunctionType::Map {
stringify!($value), "\" }") 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 std::cell::RefCell;
use codec::Codec; use codec::Codec;
use super::*; use super::*;
use serde;
use serde_json;
impl Storage for RefCell<HashMap<Vec<u8>, Vec<u8>>> { impl Storage for RefCell<HashMap<Vec<u8>, Vec<u8>>> {
fn exists(&self, key: &[u8]) -> bool { fn exists(&self, key: &[u8]) -> bool {
@@ -1580,7 +1620,6 @@ mod tests {
GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ]; GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ];
pub PUBMAPU32Required : required map [ u32 => String ]; pub PUBMAPU32Required : required map [ u32 => String ];
pub GETPUBMAPU32Required get(map_pub_get_u32_required): 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; type Origin = u32;
} }
const EXPECTED_METADATA: &str = concat!( const EXPECTED_METADATA: StorageMetadata = StorageMetadata {
r#"{ "prefix": "TestStorage", "items": { "#, prefix: DecodeDifferent::Encode("TestStorage"),
r#""U32": { "description": [ " Hello, this is doc!" ], "modifier": null, "type": "u32" }, "#, functions: DecodeDifferent::Encode(&[
r#""GETU32": { "description": [ ], "modifier": null, "type": "u32" }, "#, StorageFunctionMetadata {
r#""PUBU32": { "description": [ ], "modifier": null, "type": "u32" }, "#, name: DecodeDifferent::Encode("U32"),
r#""GETPUBU32": { "description": [ ], "modifier": null, "type": "u32" }, "#, modifier: StorageFunctionModifier::None,
r#""U32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#, ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
r#""GETU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#, documentation: DecodeDifferent::Encode(&[ " Hello, this is doc!" ]),
r#""PUBU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#, },
r#""GETPUBU32Default": { "description": [ ], "modifier": "default", "type": "u32" }, "#, StorageFunctionMetadata {
r#""U32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#, name: DecodeDifferent::Encode("GETU32"),
r#""GETU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#, modifier: StorageFunctionModifier::None,
r#""PUBU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#, ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
r#""GETPUBU32Required": { "description": [ ], "modifier": "required", "type": "u32" }, "#, documentation: DecodeDifferent::Encode(&[]),
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" } }, "#, StorageFunctionMetadata {
r#""PUBMAPU32": { "description": [ ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#, name: DecodeDifferent::Encode("PUBU32"),
r#""GETPUBMAPU32": { "description": [ ], "modifier": null, "type": { "key": "u32", "value": "String" } }, "#, modifier: StorageFunctionModifier::None,
r#""MAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#, ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
r#""GETMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#, documentation: DecodeDifferent::Encode(&[]),
r#""PUBMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#, },
r#""GETPUBMAPU32Default": { "description": [ ], "modifier": "default", "type": { "key": "u32", "value": "String" } }, "#, StorageFunctionMetadata {
r#""MAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#, name: DecodeDifferent::Encode("GETPUBU32"),
r#""GETMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#, modifier: StorageFunctionModifier::None,
r#""PUBMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }, "#, ty: StorageFunctionType::Plain(DecodeDifferent::Encode("u32")),
r#""GETPUBMAPU32Required": { "description": [ ], "modifier": "required", "type": { "key": "u32", "value": "String" } }"#, 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] #[test]
fn store_json_metadata() { fn store_metadata() {
let metadata = Module::<TraitImpl>::store_json_metadata(); let metadata = Module::<TraitImpl>::store_metadata();
assert_eq!(EXPECTED_METADATA, metadata); assert_eq!(EXPECTED_METADATA, metadata);
let _: serde::de::IgnoredAny =
serde_json::from_str(metadata).expect("Is valid json syntax");
} }
} }