mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 14:37:57 +00:00
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:
Generated
+3
-2
@@ -2578,7 +2578,6 @@ dependencies = [
|
||||
"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_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-std 0.1.0",
|
||||
"substrate-metadata 0.1.0",
|
||||
@@ -2742,7 +2741,6 @@ dependencies = [
|
||||
"substrate-bft 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-metadata 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-state-machine 0.1.0",
|
||||
"substrate-telemetry 0.3.0",
|
||||
@@ -2844,6 +2842,9 @@ name = "substrate-metadata"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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]]
|
||||
|
||||
@@ -28,7 +28,6 @@ members = [
|
||||
"core/executor",
|
||||
"core/extrinsic-pool",
|
||||
"core/keyring",
|
||||
"core/metadata",
|
||||
"core/misbehavior-check",
|
||||
"core/network",
|
||||
"core/primitives",
|
||||
@@ -46,6 +45,7 @@ members = [
|
||||
"srml/democracy",
|
||||
"srml/example",
|
||||
"srml/executive",
|
||||
"srml/metadata",
|
||||
"core/sr-primitives",
|
||||
"srml/session",
|
||||
"srml/staking",
|
||||
|
||||
@@ -18,7 +18,6 @@ parity-codec = { version = "1.1" }
|
||||
substrate-executor = { path = "../executor" }
|
||||
substrate-primitives = { path = "../primitives" }
|
||||
sr-io = { path = "../sr-io" }
|
||||
substrate-metadata = { path = "../metadata" }
|
||||
sr-primitives = { path = "../sr-primitives" }
|
||||
substrate-state-machine = { path = "../state-machine" }
|
||||
substrate-keyring = { path = "../../core/keyring" }
|
||||
|
||||
@@ -23,7 +23,6 @@ use primitives::AuthorityId;
|
||||
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::BuildStorage;
|
||||
use substrate_metadata::JsonMetadataDecodable;
|
||||
use primitives::{Blake2Hasher, RlpCodec, H256};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
@@ -254,26 +253,9 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
&self.executor
|
||||
}
|
||||
|
||||
/// Returns the runtime metadata as JSON.
|
||||
pub fn json_metadata(&self, id: &BlockId<Block>) -> error::Result<String> {
|
||||
self.executor.call(id, "json_metadata",&[])
|
||||
.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)
|
||||
})
|
||||
/// Returns the runtime metadata.
|
||||
pub fn metadata(&self, id: &BlockId<Block>) -> error::Result<Vec<u8>> {
|
||||
self.executor.call(id, "metadata",&[]).map(|v| v.return_data)
|
||||
}
|
||||
|
||||
/// 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_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 } } }"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
extern crate substrate_bft as bft;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_metadata;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_io as runtime_io;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
let block = self.unwrap_or_best(block)?;
|
||||
let metadata = self.client.json_metadata(&BlockId::Hash(block))?;
|
||||
serde_json::from_str(&metadata).map_err(Into::into)
|
||||
let metadata = self.client.metadata(&BlockId::Hash(block))?;
|
||||
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>>> {
|
||||
|
||||
@@ -133,21 +133,10 @@ pub fn run_tests(mut input: &[u8]) -> Vec<u8> {
|
||||
[stxs.len() as u8].encode()
|
||||
}
|
||||
|
||||
fn test_event_json() -> &'static str {
|
||||
"hallo"
|
||||
}
|
||||
|
||||
pub mod api {
|
||||
use system;
|
||||
impl_stubs!(
|
||||
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(),
|
||||
initialise_block => |header| system::initialise_block(header),
|
||||
execute_block => |block| system::execute_block(block),
|
||||
|
||||
+3
@@ -588,6 +588,9 @@ name = "substrate-metadata"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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]]
|
||||
|
||||
@@ -232,7 +232,7 @@ pub type Executive = executive::Executive<Runtime, Block, Balances, Balances, Al
|
||||
pub mod api {
|
||||
impl_stubs!(
|
||||
version => |()| super::VERSION,
|
||||
json_metadata => |()| super::Runtime::json_metadata(),
|
||||
metadata => |()| super::Runtime::metadata(),
|
||||
authorities => |()| super::Consensus::authorities(),
|
||||
initialise_block => |header| super::Executive::initialise_block(&header),
|
||||
apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic),
|
||||
|
||||
Generated
+3
@@ -879,6 +879,9 @@ name = "substrate-metadata"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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]]
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
@@ -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>,
|
||||
}
|
||||
@@ -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"]
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)*, )*
|
||||
);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user