diff --git a/abi/Cargo.toml b/abi/Cargo.toml index 0c5d8c481c830a69cab1b2e58dcd3e5fbfecf801..07a0ab07d359b339e4da2c88bcb128bd0766fdfa 100644 --- a/abi/Cargo.toml +++ b/abi/Cargo.toml @@ -19,6 +19,9 @@ derive_more = { version = "0.15", default-features = false, features = ["no_std" ink_abi_derive = { version = "0.1.0", path = "derive", default-features = false, optional = true } type-metadata = { git = "https://github.com/type-metadata/type-metadata.git", default-features = false, features = ["derive"] } +[dev-dependencies] +serde_json = "1.0" + [features] default = [ "std", diff --git a/abi/src/layout.rs b/abi/src/layout.rs index 038ddf122adb82cabbf214dc44813e804fddeb76..00fa9fa8f224b42fdb900f4a888f4836518cdc03 100644 --- a/abi/src/layout.rs +++ b/abi/src/layout.rs @@ -15,7 +15,11 @@ // along with ink!. If not, see . use derive_more::From; -use serde::Serialize; +use serde::{ + Serialize, + Serializer, +}; +use std::fmt::Write; use type_metadata::{ form::{ CompactForm, @@ -158,7 +162,7 @@ impl IntoCompact for LayoutField { #[serde(bound = "F::TypeId: Serialize")] pub struct LayoutRange { /// The single key for cells or the starting key address for chunks. - #[serde(rename = "range.offset")] + #[serde(rename = "range.offset", serialize_with = "serialize_key")] offset: LayoutKey, /// The amount of associated key addresses starting from the offset key. #[serde(rename = "range.len")] @@ -205,3 +209,52 @@ impl LayoutRange { } } } + +fn serialize_key(key: &LayoutKey, serializer: S) -> Result +where + S: Serializer, +{ + let bytes = key.0; + let mut hex = String::with_capacity(bytes.len() * 2 + 2); + write!(hex, "0x").expect("failed writing to string"); + for byte in &bytes { + write!(hex, "{:02x}", byte).expect("failed writing to string"); + } + + serializer.serialize_str(&hex) +} + +#[cfg(test)] +mod tests { + use super::*; + use type_metadata::{ + form::{ + Form, + MetaForm, + }, + IntoCompact, + Registry, + }; + + #[test] + fn key_must_serialize_to_hex() { + // given + let type_id = ::TypeId::new::(); + let offset = LayoutKey([1; 32]); + let cs: LayoutRange = LayoutRange { + offset, + len: 1337, + elem_ty: type_id, + }; + let mut registry = Registry::new(); + + // when + let json = serde_json::to_string(&cs.into_compact(&mut registry)).unwrap(); + + // then + assert_eq!( + json, + "{\"range.offset\":\"0x0101010101010101010101010101010101010101010101010101010101010101\",\"range.len\":1337,\"range.elem_type\":1}" + ); + } +} diff --git a/abi/src/specs.rs b/abi/src/specs.rs index 045dd1102cec5563876cac10b275f159fee3fe6b..df9a46fc70b74ace67c57f481f214cc762ea3a98 100644 --- a/abi/src/specs.rs +++ b/abi/src/specs.rs @@ -15,7 +15,10 @@ // along with ink!. If not, see . use core::marker::PhantomData; -use serde::Serialize; +use serde::{ + Serialize, + Serializer, +}; use type_metadata::{ form::{ CompactForm, @@ -190,7 +193,8 @@ pub struct ConstructorSpec { /// The name of the message. name: F::String, /// The selector hash of the message. - selector: u32, + #[serde(serialize_with = "serialize_selector")] + selector: [u8; 4], /// The parameters of the deploy handler. args: Vec>, /// The deploy handler documentation. @@ -234,7 +238,7 @@ impl ConstructorSpec { ConstructorSpecBuilder { spec: Self { name, - selector: 0, + selector: [0u8; 4], args: Vec::new(), docs: Vec::new(), }, @@ -245,7 +249,7 @@ impl ConstructorSpec { impl ConstructorSpecBuilder> { /// Sets the function selector of the message. - pub fn selector(self, selector: u32) -> ConstructorSpecBuilder { + pub fn selector(self, selector: [u8; 4]) -> ConstructorSpecBuilder { ConstructorSpecBuilder { spec: ConstructorSpec { selector, @@ -294,7 +298,8 @@ pub struct MessageSpec { /// The name of the message. name: F::String, /// The selector hash of the message. - selector: u32, + #[serde(serialize_with = "serialize_selector")] + selector: [u8; 4], /// If the message is allowed to mutate the contract state. mutates: bool, /// The parameters of the message. @@ -333,7 +338,7 @@ impl MessageSpec { MessageSpecBuilder { spec: Self { name, - selector: 0, + selector: [0u8; 4], mutates: false, args: Vec::new(), return_type: ReturnTypeSpec::new(None), @@ -358,7 +363,10 @@ pub struct MessageSpecBuilder { impl MessageSpecBuilder, M, R> { /// Sets the function selector of the message. - pub fn selector(self, selector: u32) -> MessageSpecBuilder { + pub fn selector( + self, + selector: [u8; 4], + ) -> MessageSpecBuilder { MessageSpecBuilder { spec: MessageSpec { selector, @@ -795,3 +803,38 @@ impl MessageParamSpecBuilder { self.spec } } + +fn serialize_selector(s: &[u8; 4], serializer: S) -> Result +where + S: Serializer, +{ + let hex = format!("0x{:02X}{:02X}{:02X}{:02X}", s[0], s[1], s[2], s[3]); + serializer.serialize_str(&hex) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn construct_selector_must_serialize_to_hex() { + // given + let name = ::String::from("foo"); + let cs: ConstructorSpec = ConstructorSpec { + name, + selector: 123456789u32.to_be_bytes(), + args: Vec::new(), + docs: Vec::new(), + }; + let mut registry = Registry::new(); + + // when + let json = serde_json::to_string(&cs.into_compact(&mut registry)).unwrap(); + + // then + assert_eq!( + json, + "{\"name\":1,\"selector\":\"0x075BCD15\",\"args\":[],\"docs\":[]}" + ); + } +} diff --git a/core/src/env/calls.rs b/core/src/env/calls.rs index aa83f8254e8e6385b16010c4ad70eb3625c8e759..24fa85851527f95b4ad26a0a175a1984de111478 100644 --- a/core/src/env/calls.rs +++ b/core/src/env/calls.rs @@ -40,10 +40,9 @@ struct CallAbi { impl CallAbi { /// Creates new call ABI data for the given selector. - pub fn new(selector: u32) -> Self { - let bytes = selector.to_le_bytes(); + pub fn new(selector: [u8; 4]) -> Self { Self { - raw: vec![bytes[0], bytes[1], bytes[2], bytes[3]], + raw: vec![selector[0], selector[1], selector[2], selector[3]], } } @@ -177,7 +176,7 @@ where E::Balance: Default, { /// Instantiates an evaluatable (returns data) remote smart contract call. - pub fn eval(account_id: E::AccountId, selector: u32) -> Self { + pub fn eval(account_id: E::AccountId, selector: [u8; 4]) -> Self { Self { account_id, gas_limit: 0, @@ -194,7 +193,7 @@ where E::Balance: Default, { /// Instantiates a non-evaluatable (returns no data) remote smart contract call. - pub fn invoke(account_id: E::AccountId, selector: u32) -> Self { + pub fn invoke(account_id: E::AccountId, selector: [u8; 4]) -> Self { Self { account_id, gas_limit: 0, diff --git a/lang/src/gen/abi.rs b/lang/src/gen/abi.rs index 9985881c4808d4f07328aa840e06be8b6e9fa8cd..9417b3f937f02a7492c6ef11a03da86707b6c740 100644 --- a/lang/src/gen/abi.rs +++ b/lang/src/gen/abi.rs @@ -21,6 +21,7 @@ use crate::{ ast, + gen::selector_to_expr, hir, }; use proc_macro2::TokenStream as TokenStream2; @@ -121,7 +122,7 @@ fn generate_abi_constructor(contract: &hir::Contract) -> TokenStream2 { quote! { ink_abi::ConstructorSpec::new("on_deploy") - .selector(0) + .selector([0u8; 4]) .args(vec![ #(#args ,)* ]) @@ -136,7 +137,7 @@ fn generate_abi_messages<'a>( contract: &'a hir::Contract, ) -> impl Iterator + 'a { contract.messages.iter().map(|message| { - let selector = message.selector(); + let selector = selector_to_expr(message.selector()); let is_mut = message.is_mut(); let docs = message.docs().map(trim_doc_string); let name = message.sig.ident.to_string(); diff --git a/lang/src/gen/as_dependency.rs b/lang/src/gen/as_dependency.rs index 1c194597908f57fb669e62aff42db310a6be6e71..3ee294d7b04c987573aadb330577b165874d44c0 100644 --- a/lang/src/gen/as_dependency.rs +++ b/lang/src/gen/as_dependency.rs @@ -24,6 +24,7 @@ use crate::{ ast, + gen::selector_to_expr, hir, }; use proc_macro2::TokenStream as TokenStream2; @@ -236,7 +237,7 @@ fn generate_call_enhancer_messages<'a>( .map(|ident| quote! { #ident }); let output = &message.sig.decl.output; let (_impl_generics, type_generics, where_clause) = message.sig.decl.generics.split_for_impl(); - let selector = message.selector(); + let selector = selector_to_expr(message.selector()); match output { syn::ReturnType::Default => quote_spanned! { ident.span() => #(#attrs)* diff --git a/lang/src/gen/build.rs b/lang/src/gen/build.rs index cf62c8d52ea62817ae8f27575cd9a4efa0b8ffdb..f820782c07e5f6ef6b5f31f55bb4a96a40518e86 100644 --- a/lang/src/gen/build.rs +++ b/lang/src/gen/build.rs @@ -21,11 +21,11 @@ use crate::{ ast, + gen::selector_to_expr, hir, }; use proc_macro2::{ Ident, - Span, TokenStream as TokenStream2, }; use quote::{ @@ -473,12 +473,7 @@ fn codegen_for_messages(tokens: &mut TokenStream2, contract: &hir::Contract) { for attr in &message.attrs { attr.to_tokens(&mut content) } - let msg_selector = message.selector(); - let msg_id = syn::LitInt::new( - msg_selector.into(), - syn::IntSuffix::None, - Span::call_site(), - ); + let msg_id = selector_to_expr(message.selector()); msg_id.to_tokens(&mut content); ]>::default().to_tokens(&mut content); use heck::CamelCase as _; diff --git a/lang/src/gen/mod.rs b/lang/src/gen/mod.rs index 68ae147cfc2e0f40d197f8f4e2e0dd1036bde46f..7be704f96235ad9ffb4475ed25dbcc779e7e8e5c 100644 --- a/lang/src/gen/mod.rs +++ b/lang/src/gen/mod.rs @@ -23,6 +23,10 @@ mod test; use crate::hir; use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use syn::{ + parse_str, + Expr, +}; /// Generates code for the given contract. /// @@ -39,3 +43,13 @@ pub fn generate_code(contract: &hir::Contract) -> TokenStream2 { as_dependency::generate_code(&mut tokens, contract); tokens } + +/// The function is required because syn doesn't provide a +/// `ToTokens` implementation for `[u8; 4]`. +fn selector_to_expr(selector: [u8; 4]) -> Expr { + let selector = format!( + "[{}, {}, {}, {}]", + selector[0], selector[1], selector[2], selector[3] + ); + parse_str::(&selector).expect("failed to parse selector") +} diff --git a/lang/src/hir.rs b/lang/src/hir.rs index 6d65d89229b871cbed67532558ca68067b6944b7..6ce412a19d84555d94d47959b43369d5dcbe998c 100644 --- a/lang/src/hir.rs +++ b/lang/src/hir.rs @@ -507,14 +507,14 @@ impl Message { } /// Returns the message selector for this message. - pub fn selector(&self) -> u32 { + pub fn selector(&self) -> [u8; 4] { raw_message_selector(self.sig.ident.to_string().as_str()) } } -fn raw_message_selector(name: &str) -> u32 { +fn raw_message_selector(name: &str) -> [u8; 4] { let keccak = ink_utils::hash::keccak256(name.as_bytes()); - u32::from_le_bytes([keccak[0], keccak[1], keccak[2], keccak[3]]) + [keccak[3], keccak[2], keccak[1], keccak[0]] } impl From<&ast::ItemImplMethod> for Message { @@ -570,8 +570,8 @@ mod tests { #[test] fn message_selectors() { - assert_eq!(raw_message_selector("inc"), 257544423); - assert_eq!(raw_message_selector("get"), 4266279973); - assert_eq!(raw_message_selector("compare"), 363906316); + assert_eq!(raw_message_selector("inc"), [15, 89, 208, 231]); + assert_eq!(raw_message_selector("get"), [254, 74, 68, 37]); + assert_eq!(raw_message_selector("compare"), [21, 176, 197, 12]); } } diff --git a/lang/src/old_abi.rs b/lang/src/old_abi.rs index 6e6d410e89925f37e98fb2918fa350e250694f52..b491021f102e2035c97cf627bc57b216c98d399b 100644 --- a/lang/src/old_abi.rs +++ b/lang/src/old_abi.rs @@ -478,9 +478,11 @@ impl TryFrom<&hir::Message> for MessageDescription { type Error = syn::Error; fn try_from(message: &hir::Message) -> Result { + let s = message.selector(); + let selector = u32::from_le_bytes([s[3], s[2], s[1], s[0]]).into(); Ok(Self { name: message.sig.ident.to_string(), - selector: message.selector().into(), + selector, mutates: message.is_mut(), args: { message diff --git a/lang/src/tests/events.rs b/lang/src/tests/events.rs index cdc8976d6d96f308fd07eb2f2d00aef6da37c8fc..c8aeba9e731c8a1aaea87549668b12d292159955 100644 --- a/lang/src/tests/events.rs +++ b/lang/src/tests/events.rs @@ -115,13 +115,13 @@ fn contract_compiles() { /// # Note /// /// Also emits an event. - 257544423 => Inc(); + [15, 89, 208, 231] => Inc(); /// Decrements the internal counter. /// /// # Note /// /// Also emits an event. - 1772705147 => Dec(); + [105, 169, 85, 123] => Dec(); } } @@ -310,14 +310,14 @@ fn contract_compiles() { ink_abi::ContractSpec::new("CallCounter") .constructors(vec![ ink_abi::ConstructorSpec::new("on_deploy") - .selector(0) + .selector([0u8; 4]) .args(vec![]) .docs(vec![]) .done() ]) .messages(vec![ ink_abi::MessageSpec::new("inc") - .selector(257544423u32) + .selector([15, 89, 208, 231]) .mutates(true) .args(vec![]) .docs(vec![ @@ -332,7 +332,7 @@ fn contract_compiles() { ) .done(), ink_abi::MessageSpec::new("dec") - .selector(1772705147u32) + .selector([105, 169, 85, 123]) .mutates(true) .args(vec![]) .docs(vec![ @@ -496,7 +496,7 @@ fn contract_compiles() { /// Also emits an event. pub fn inc(self,) -> ink_core::env::CallBuilder { ink_core::env::CallBuilder::::invoke( - self.contract.account_id.clone(), 257544423u32) + self.contract.account_id.clone(), [15, 89, 208, 231]) } /// Decrements the internal counter. @@ -506,7 +506,7 @@ fn contract_compiles() { /// Also emits an event. pub fn dec(self,) -> ink_core::env::CallBuilder { ink_core::env::CallBuilder::::invoke( - self.contract.account_id.clone(), 1772705147u32) + self.contract.account_id.clone(), [105, 169, 85, 123]) } } } diff --git a/lang/src/tests/flipper.rs b/lang/src/tests/flipper.rs index abad0ced0fdfbf6936fc6312c6da28ae0dc7fac7..9f57f9bc44e3b261d066eadf122126089fb06c68 100644 --- a/lang/src/tests/flipper.rs +++ b/lang/src/tests/flipper.rs @@ -90,9 +90,9 @@ fn contract_compiles() { ink_model::messages! { /// Flips the internal boolean. - 970692492 => Flip(); + [57, 219, 151, 140] => Flip(); /// Returns the internal boolean. - 4266279973 => Get() -> bool; + [254, 74, 68, 37] => Get() -> bool; } } @@ -208,7 +208,7 @@ fn contract_compiles() { ink_abi::ContractSpec::new("Flipper") .constructors(vec![ ink_abi::ConstructorSpec::new("on_deploy") - .selector(0) + .selector([0u8; 4]) .args(vec![]) .docs(vec![ "The internal boolean is initialized with `true`.", @@ -217,14 +217,14 @@ fn contract_compiles() { ]) .messages(vec![ ink_abi::MessageSpec::new("flip") - .selector(970692492u32) + .selector([57, 219, 151, 140]) .mutates(true) .args(vec![]) .docs(vec!["Flips the internal boolean.",]) .returns(ink_abi::ReturnTypeSpec::new(None)) .done(), ink_abi::MessageSpec::new("get") - .selector(4266279973u32) + .selector([254, 74, 68, 37]) .mutates(false) .args(vec![]) .docs(vec!["Returns the internal boolean.",]) @@ -345,7 +345,7 @@ fn contract_compiles() { /// Returns the internal boolean. pub fn get(self,) -> ink_core::env::CallBuilder> { ink_core::env::CallBuilder::eval( - self.contract.account_id.clone(), 4266279973u32 + self.contract.account_id.clone(), [254, 74, 68, 37] ) } } @@ -354,7 +354,7 @@ fn contract_compiles() { /// Flips the internal boolean. pub fn flip(self,) -> ink_core::env::CallBuilder { ink_core::env::CallBuilder::::invoke( - self.contract.account_id.clone(), 970692492u32) + self.contract.account_id.clone(), [57, 219, 151, 140]) } } } diff --git a/lang/src/tests/incrementer.rs b/lang/src/tests/incrementer.rs index 577a24ed65d22515ba6ed9785f7b5bb6a65bf5fa..ad2cdb7878554d390131e386226ca80a0dc07a9b 100644 --- a/lang/src/tests/incrementer.rs +++ b/lang/src/tests/incrementer.rs @@ -97,11 +97,11 @@ fn contract_compiles() { ink_model::messages! { /// Increments the internal counter. - 257544423 => Inc(by: u32); + [15, 89, 208, 231] => Inc(by: u32); /// Returns the internal counter. - 4266279973 => Get() -> u32; + [254, 74, 68, 37] => Get() -> u32; /// Returns `true` if `x` is greater than the internal value. - 363906316 => Compare(x: u32) -> bool; + [21, 176, 197, 12] => Compare(x: u32) -> bool; } } @@ -231,7 +231,7 @@ fn contract_compiles() { ink_abi::ContractSpec::new("Incrementer") .constructors(vec![ ink_abi::ConstructorSpec::new("on_deploy") - .selector(0) + .selector([0u8; 4]) .args(vec![ ink_abi::MessageParamSpec::new("init_value") .of_type( @@ -248,7 +248,7 @@ fn contract_compiles() { ]) .messages(vec![ ink_abi::MessageSpec::new("inc") - .selector(257544423u32) + .selector([15, 89, 208, 231]) .mutates(true) .args(vec![ ink_abi::MessageParamSpec::new("by") @@ -267,7 +267,7 @@ fn contract_compiles() { ) .done(), ink_abi::MessageSpec::new("get") - .selector(4266279973u32) + .selector([254, 74, 68, 37]) .mutates(false) .args(vec![]) .docs(vec![ @@ -282,7 +282,7 @@ fn contract_compiles() { ) .done(), ink_abi::MessageSpec::new("compare") - .selector(363906316u32) + .selector([21, 176, 197, 12]) .mutates(false) .args(vec![ ink_abi::MessageParamSpec::new("x") @@ -432,7 +432,7 @@ fn contract_compiles() { /// Returns the internal counter. pub fn get(self,) -> ink_core::env::CallBuilder> { ink_core::env::CallBuilder::eval( - self.contract.account_id.clone(), 4266279973u32 + self.contract.account_id.clone(), [254, 74, 68, 37] ) } @@ -443,7 +443,7 @@ fn contract_compiles() { .contract .account_id .clone(), - 363906316u32 + [21, 176, 197, 12] ).push_arg(&x) } } @@ -452,7 +452,7 @@ fn contract_compiles() { /// Increments the internal counter. pub fn inc(self, by: u32,) -> ink_core::env::CallBuilder { ink_core::env::CallBuilder::::invoke( - self.contract.account_id.clone(), 257544423u32 + self.contract.account_id.clone(), [15, 89, 208, 231] ).push_arg(&by) } } diff --git a/lang/src/tests/noop.rs b/lang/src/tests/noop.rs index 012ebdf41f09d47e579f52dd1eeedee985a62f29..abaa7f5d97d01c0ff3460f6ae75a31496e926ebd 100644 --- a/lang/src/tests/noop.rs +++ b/lang/src/tests/noop.rs @@ -164,7 +164,7 @@ fn contract_compiles() { ink_abi::ContractSpec::new("Noop") .constructors(vec![ ink_abi::ConstructorSpec::new("on_deploy") - .selector(0) + .selector([0u8; 4]) .args(vec![]) .docs(vec![ "Does nothing to initialize itself.", diff --git a/model/src/msg.rs b/model/src/msg.rs index a7629f151643fb9f55525e514762686951775d09..c53d34c7cc7b8dfd72329e1dda992baba1b0f464 100644 --- a/model/src/msg.rs +++ b/model/src/msg.rs @@ -40,44 +40,122 @@ pub trait Message { /// Defines messages for contracts with less boilerplate code. #[macro_export] macro_rules! messages { - ( - $( #[$msg_meta:meta] )* - $msg_id:literal => $msg_name:ident ( - $( $param_name:ident : $param_ty:ty ),* - ) -> $ret_ty:ty ; - - $($rest:tt)* - ) => { - $( #[$msg_meta] )* - #[derive(Copy, Clone)] - pub(crate) struct $msg_name; - - impl $crate::Message for $msg_name { - type Input = ($($param_ty),*); - type Output = $ret_ty; - - const ID: $crate::MessageHandlerSelector = $crate::MessageHandlerSelector::new($msg_id); - const NAME: &'static str = stringify!($msg_name); - } - - messages!($($rest)*); - }; - ( - $( #[$msg_meta:meta] )* - $msg_id:literal => $msg_name:ident ( - $( $param_name:ident : $param_ty:ty ),* - ) ; - - $($rest:tt)* - ) => { - messages!( - $( #[$msg_meta] )* - $msg_id => $msg_name ( - $( $param_name : $param_ty ),* - ) -> (); - - $($rest)* - ); - }; - () => {}; + // When parsing the macro with a doc comment Rust cannot decide + // unambiguously if it should match the doc comment to `meta` or + // `expr`. Hence we introduce a `@delimiter` between the two of them. + // The first two rules match for macro invocations containing this + // delimiter, the subsequent ones add the delimiter if it's missing. + + // With delimiter and a metavariable (typically a doc comment). + ( + $( #[$msg_meta:meta] )+ + @delimiter $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) -> $ret_ty:ty ; + $($rest:tt)* + ) => { + $( #[$msg_meta] )+ + #[derive(Copy, Clone)] + pub(crate) struct $msg_name; + + impl $crate::Message for $msg_name { + type Input = ($($param_ty),*); + type Output = $ret_ty; + + const ID: $crate::MessageHandlerSelector = $crate::MessageHandlerSelector::new($msg_id); + const NAME: &'static str = stringify!($msg_name); + } + + messages!($($rest)*); + }; + + // With delimiter and no metavariable. + ( + @delimiter $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) -> $ret_ty:ty ; + + $($rest:tt)* + ) => { + #[derive(Copy, Clone)] + pub(crate) struct $msg_name; + + impl $crate::Message for $msg_name { + type Input = ($($param_ty),*); + type Output = $ret_ty; + + const ID: $crate::MessageHandlerSelector = $crate::MessageHandlerSelector::new($msg_id); + const NAME: &'static str = stringify!($msg_name); + } + + messages!($($rest)*); + }; + + // Without delimiter, with a metavariable and a return type. + ( + $( #[$msg_meta:meta] )+ + $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) -> $ret_ty:ty ; + + $($rest:tt)* + ) => { + messages!( + $( #[$msg_meta] )+ + @delimiter $msg_id => $msg_name ( + $( $param_name : $param_ty ),* + ) -> $ret_ty; + $($rest)* + ); + }; + + // Without delimiter, with a metavariable but no return type. + ( + $( #[$msg_meta:meta] )+ + $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) ; + + $($rest:tt)* + ) => { + messages!( + $( #[$msg_meta] )+ + @delimiter $msg_id => $msg_name ( + $( $param_name : $param_ty ),* + ) -> (); + $($rest)* + ); + }; + + // Without delimiter, no metavariable but a return type. + ( + $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) -> $ret_ty:ty ; + $($rest:tt)* + ) => { + messages!( + @delimiter $msg_id => $msg_name ( + $( $param_name : $param_ty ),* + ) -> $ret_ty; + $($rest)* + ); + }; + + // Without delimiter, no metavariable and no return type. + ( + $msg_id:expr => $msg_name:ident ( + $( $param_name:ident : $param_ty:ty ),* + ) ; + $($rest:tt)* + ) => { + messages!( + @delimiter $msg_id => $msg_name ( + $( $param_name : $param_ty ),* + ) -> (); + $($rest)* + ); + }; + + () => {}; } diff --git a/model/src/msg_handler.rs b/model/src/msg_handler.rs index b9e6aa00803758a1a515eeef538b44eca1842d58..35b077b1d3f736b24a590c2abc78ba37622a7a91 100644 --- a/model/src/msg_handler.rs +++ b/model/src/msg_handler.rs @@ -103,11 +103,11 @@ impl CallData { /// A hash to identify a called function. #[derive(Copy, Clone, PartialEq, Eq, Decode)] -pub struct MessageHandlerSelector(u32); +pub struct MessageHandlerSelector([u8; 4]); impl MessageHandlerSelector { /// Creates a new message handler selector from the given value. - pub const fn new(raw: u32) -> Self { + pub const fn new(raw: [u8; 4]) -> Self { Self(raw) } } diff --git a/model/tests/incrementer.rs b/model/tests/incrementer.rs index 17a3b5f718c7caf4b45ddb9e79e05790cc28c419..e4497b2ac749dc5cf5199abd85adc1abd9ddf7f4 100644 --- a/model/tests/incrementer.rs +++ b/model/tests/incrementer.rs @@ -38,9 +38,9 @@ state! { messages! { /// Increases the storage value by the given amount. - 0 => Inc(by: u32); + [0u8; 4] => Inc(by: u32); /// Returns the storage value. - 1 => Get() -> u32; + [1, 0, 0, 0] => Get() -> u32; } #[rustfmt::skip] diff --git a/model/tests/noop.rs b/model/tests/noop.rs index bfdb7758bd3fb25fea4c82162d1610e55d8dbdf7..7f2a7c95dbd8b772780dacd95b8c55eec94a2e40 100644 --- a/model/tests/noop.rs +++ b/model/tests/noop.rs @@ -34,7 +34,7 @@ state! { } messages! { - 0 => DoNothing(); + [0u8; 4] => DoNothing(); } impl Noop {