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 {