Switch to derive(Encode, Decode) for Call (#2178)

* Add some tests

* More tests

* Switch to `derive(Encode, Decode)` for `Call`

* Update lock files

* Simplify the macro cases
This commit is contained in:
Bastian Köcher
2019-04-03 11:59:57 +02:00
committed by Gav Wood
parent b3931d3e2a
commit e902c54399
6 changed files with 319 additions and 353 deletions
+160 -194
View File
@@ -615,6 +615,113 @@ macro_rules! decl_module {
}
};
// Declare a `Call` variant parameter that should be encoded `compact`.
(@create_call_enum
$( #[$attr:meta] )*
$call_type:ident;
<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
{ $( $generated_variants:tt )* }
{ $( $current_params:tt )* }
variant $fn_name:ident;
$( #[doc = $doc_attr:tt] )*
#[compact]
$type:ty;
$( $rest:tt )*
) => {
$crate::decl_module! {
@create_call_enum
$( #[$attr] )*
$call_type;
<$trait_instance: $trait_name $(<I>, $instance: $instantiable $(= $module_default_instance)? )?>
{ $( $generated_variants )* }
{
$( $current_params )*
#[codec(compact)]
$type,
}
variant $fn_name;
$( $rest )*
}
};
// Declare a `Call` variant parameter.
(@create_call_enum
$( #[$attr:meta] )*
$call_type:ident;
<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
{ $( $generated_variants:tt )* }
{ $( $current_params:tt )* }
variant $fn_name:ident;
$(#[doc = $doc_attr:tt])*
$type:ty;
$( $rest:tt )*
) => {
$crate::decl_module! {
@create_call_enum
$( #[$attr] )*
$call_type;
<$trait_instance: $trait_name $(<I>, $instance: $instantiable $(= $module_default_instance)? )?>
{ $( $generated_variants )* }
{
$( $current_params )*
$type,
}
variant $fn_name;
$( $rest )*
}
};
(@create_call_enum
$( #[$attr:meta] )*
$call_type:ident;
<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
{ $( $generated_variants:tt )* }
{ $( $current_params:tt )* }
variant $fn_name:ident;
$(#[doc = $doc_attr:tt])*
$(
variant $next_fn_name:ident;
$( $rest:tt )*
)?
) => {
$crate::decl_module! {
@create_call_enum
$( #[$attr] )*
$call_type;
<$trait_instance: $trait_name $(<I>, $instance: $instantiable $(= $module_default_instance)? )?>
{
$( $generated_variants )*
#[allow(non_camel_case_types)]
$(#[doc = $doc_attr])*
$fn_name (
$( $current_params )*
),
}
{}
$(
variant $next_fn_name;
$( $rest )*
)?
}
};
(@create_call_enum
$( #[$attr:meta] )*
$call_type:ident;
<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
{ $( $generated_variants:tt )* }
{}
) => {
#[derive($crate::codec::Encode, $crate::codec::Decode)]
$( #[$attr] )*
pub enum $call_type<$trait_instance: $trait_name$(<I>, $instance: $instantiable $( = $module_default_instance)?)?> {
#[doc(hidden)]
#[codec(skip)]
__PhantomItem($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never),
$( $generated_variants )*
}
};
// The main macro expansion that actually renders the module code.
(@imp
@@ -637,17 +744,7 @@ macro_rules! decl_module {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
// FIXME: switching based on std feature is because of an issue in
// serde-derive for when we attempt to derive `Deserialize` on these types,
// in a situation where we've imported `srml_support` as another name.
#[cfg(feature = "std")]
pub struct $mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable $( = $module_default_instance)?)?>(::std::marker::PhantomData<($trait_instance $(, $instance)?)>);
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
#[cfg(not(feature = "std"))]
pub struct $mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable $( = $module_default_instance)?)?>(::core::marker::PhantomData<($trait_instance $(, $instance)?)>);
pub struct $mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable $( = $module_default_instance)?)?>($crate::rstd::marker::PhantomData<($trait_instance $(, $instance)?)>);
$crate::decl_module! {
@impl_on_initialize
@@ -692,27 +789,20 @@ macro_rules! decl_module {
)*
}
#[cfg(feature = "std")]
$(#[$attr])*
pub enum $call_type<$trait_instance: $trait_name$(<I>, $instance: $instantiable $( = $module_default_instance)?)?> {
#[doc(hidden)]
__PhantomItem(::std::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never),
$crate::decl_module! {
@create_call_enum
$( #[$attr] )*
$call_type;
<$trait_instance: $trait_name $(<I>, $instance: $instantiable $(= $module_default_instance)? )?>
{}
{}
$(
#[allow(non_camel_case_types)]
variant $fn_name;
$(#[doc = $doc_attr])*
$fn_name ( $( $param ),* ),
)*
}
#[cfg(not(feature = "std"))]
$(#[$attr])*
pub enum $call_type<$trait_instance: $trait_name$(<I>, $instance: $instantiable $( = $module_default_instance)?)?> {
#[doc(hidden)]
__PhantomItem(::core::marker::PhantomData<($trait_instance $(, $instance)?)>, $crate::dispatch::Never),
$(
#[allow(non_camel_case_types)]
$(#[doc = $doc_attr])*
$fn_name ( $( $param ),* ),
$(
$(#[$codec_attr])*
$param;
)*
)*
}
@@ -775,18 +865,6 @@ macro_rules! decl_module {
}
}
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Decode for $call_type<$trait_instance $(, $instance)?> {
fn decode<Input: $crate::dispatch::Input>(input: &mut Input) -> Option<Self> {
let _input_id = input.read_byte()?;
$crate::__impl_decode!(input; _input_id; 0; $call_type; $( fn $fn_name( $( $(#[$codec_attr on type $param])* $param_name ),* ); )*)
}
}
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Encode for $call_type<$trait_instance $(, $instance)?> {
fn encode_to<W: $crate::dispatch::Output>(&self, _dest: &mut W) {
$crate::__impl_encode!(_dest; *self; 0; $call_type; $( fn $fn_name( $( $(#[$codec_attr on type $param])* $param_name ),* ); )*);
}
}
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Dispatchable
for $call_type<$trait_instance $(, $instance)?>
{
@@ -826,131 +904,6 @@ macro_rules! decl_module {
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_decode {
(
$input:expr;
$input_id:expr;
$fn_id:expr;
$call_type:ident;
fn $fn_name:ident(
$( $(#[$codec_attr:ident on type $param:ty])* $param_name:ident ),*
);
$($rest:tt)*
) => {
{
if $input_id == ($fn_id) {
$(
$crate::__impl_decode!(@decode
$(#[$codec_attr on type $param])*
$param_name;
$input;
);
)*
return Some($call_type:: $fn_name( $( $param_name ),* ));
}
$crate::__impl_decode!($input; $input_id; $fn_id + 1; $call_type; $($rest)*)
}
};
(
$input:expr;
$input_id:expr;
$fn_id:expr;
$call_type:ident;
) => {
None
};
(@decode
#[compact on type $param:ty]
$param_name:ident;
$input:expr;
) => {
let $param_name = <<$param as $crate::dispatch::HasCompact>::Type as $crate::dispatch::Decode>::decode($input)?.into();
};
(@decode
$param_name:ident;
$input:expr;
) => {
let $param_name = $crate::dispatch::Decode::decode($input)?;
};
(@decode
$(#[$codec_attr:ident on type])*
$param_name:ident;
$input:expr;
) => {
compile_error!(concat!(
"Invalid attribute for parameter `",
stringify!($param_name),
"`, the following attributes are supported: `#[compact]`"
))
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_encode {
(
$dest:expr;
$self:expr;
$fn_id:expr;
$call_type:ident;
fn $fn_name:ident(
$( $(#[$codec_attr:ident on type $param:ty])* $param_name:ident ),*
);
$($rest:tt)*
) => {
{
if let $call_type::$fn_name(
$(
ref $param_name
),*
) = $self {
$dest.push_byte(($fn_id) as u8);
$(
$crate::__impl_encode!(@encode_as
$(#[$codec_attr on type $param])*
$param_name;
$dest;
);
)*
}
$crate::__impl_encode!($dest; $self; $fn_id + 1; $call_type; $($rest)*)
}
};
(
$dest:expr;
$self:expr;
$fn_id:expr;
$call_type:ident;
) => {{}};
(@encode_as
#[compact on type $param:ty]
$param_name:ident;
$dest:expr;
) => {
<<$param as $crate::dispatch::HasCompact>::Type as $crate::dispatch::EncodeAsRef<$param>>::RefType::from($param_name).encode_to($dest);
};
(@encode_as
$param_name:ident;
$dest:expr;
) => {
$param_name.encode_to($dest);
};
(@encode_as
$(#[$codec_attr:ident on type $param:ty])*
$param_name:ident;
$dest:expr;
) => {
compile_error!(concat!(
"Invalid attribute for parameter `", stringify!($param_name),
"`, the following attributes are supported: `#[compact]`"
))
};
}
pub trait IsSubType<T: Callable> {
fn is_aux_sub_type(&self) -> Option<&<T as Callable>::Call>;
}
@@ -967,14 +920,13 @@ macro_rules! impl_outer_dispatch {
}
) => {
$(#[$attr])*
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum $call_type {
$(
$camelcase ( $crate::dispatch::CallableCallFor<$camelcase> )
,)*
}
$crate::__impl_outer_dispatch_common! { $call_type, $($camelcase,)* }
impl $crate::dispatch::Dispatchable for $call_type {
type Origin = $origin;
type Trait = $call_type;
@@ -1000,28 +952,6 @@ macro_rules! impl_outer_dispatch {
}
}
/// Implement a meta-dispatch module to dispatch to other dispatchers.
#[macro_export]
#[doc(hidden)]
macro_rules! __impl_outer_dispatch_common {
(
$call_type:ident, $( $camelcase:ident, )*
) => {
impl $crate::dispatch::Decode for $call_type {
fn decode<I: $crate::dispatch::Input>(input: &mut I) -> Option<Self> {
let input_id = input.read_byte()?;
$crate::__impl_decode!(input; input_id; 0; $call_type; $( fn $camelcase ( outer_dispatch_param ); )*)
}
}
impl $crate::dispatch::Encode for $call_type {
fn encode_to<W: $crate::dispatch::Output>(&self, dest: &mut W) {
$crate::__impl_encode!(dest; *self; 0; $call_type; $( fn $camelcase( outer_dispatch_param ); )*)
}
}
}
}
/// Implement metadata for dispatch.
#[macro_export]
#[doc(hidden)]
@@ -1166,6 +1096,7 @@ mod tests {
fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() }
fn aux_3() -> Result { unreachable!() }
fn aux_4(_data: i32) -> Result { unreachable!() }
fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() }
fn on_initialize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialize") } }
fn on_finalize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalize") } }
@@ -1219,7 +1150,21 @@ mod tests {
}
]),
documentation: DecodeDifferent::Encode(&[]),
}
},
FunctionMetadata {
name: DecodeDifferent::Encode("aux_5"),
arguments: DecodeDifferent::Encode(&[
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("_data"),
ty: DecodeDifferent::Encode("i32"),
},
FunctionArgumentMetadata {
name: DecodeDifferent::Encode("_data2"),
ty: DecodeDifferent::Encode("Compact<u32>")
}
]),
documentation: DecodeDifferent::Encode(&[]),
},
];
struct TraitImpl {}
@@ -1237,9 +1182,30 @@ mod tests {
#[test]
fn compact_attr() {
let call: Call<TraitImpl> = Call::aux_1(0);
let call: Call<TraitImpl> = Call::aux_1(1);
let encoded = call.encode();
assert_eq!(encoded.len(), 2);
assert_eq!(2, encoded.len());
assert_eq!(vec![1, 4], encoded);
let call: Call<TraitImpl> = Call::aux_5(1, 2);
let encoded = call.encode();
assert_eq!(6, encoded.len());
assert_eq!(vec![5, 1, 0, 0, 0, 8], encoded);
}
#[test]
fn encode_is_correct_and_decode_works() {
let call: Call<TraitImpl> = Call::aux_0();
let encoded = call.encode();
assert_eq!(vec![0], encoded);
let decoded = Call::<TraitImpl>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, call);
let call: Call<TraitImpl> = Call::aux_2(32, "hello".into());
let encoded = call.encode();
assert_eq!(vec![2, 32, 0, 0, 0, 20, 104, 101, 108, 108, 111], encoded);
let decoded = Call::<TraitImpl>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, call);
}
#[test]