diff --git a/benchmarks/bench_data.json b/benchmarks/bench_data.json index 8ffd80c0..19c449eb 100644 --- a/benchmarks/bench_data.json +++ b/benchmarks/bench_data.json @@ -1,32 +1,32 @@ { "compute": { - "median": 450514036959 + "median": 450554650806 }, "alloc": { - "0": 564376739, - "12": 567864696, - "143": 727298127, - "986": 828290311, - "10945": 2019067671, - "46367": 6404351520, - "121392": 16859084038, - "317810": 43147409792 + "0": 601838097, + "12": 605326124, + "143": 764788566, + "986": 865780806, + "10945": 2196386851, + "46367": 6441842127, + "121392": 16896609428, + "317810": 43184935210 }, "counter": { - "async_call": 851480134, - "sync_call": 678859589 + "async_call": 882890228, + "sync_call": 711875426 }, "cross_program": { - "median": 2436719419 + "median": 2438503869 }, "redirect": { - "median": 3473474864 + "median": 3543826931 }, "message_stack": { - "0": 799109045, - "1": 3769557503, - "5": 15692980666, - "10": 29591871735, - "20": 63988962371 + "0": 824309364, + "1": 3877712516, + "5": 16133299136, + "10": 33110719037, + "20": 66299847951 } } \ No newline at end of file diff --git a/benchmarks/ping-pong/app/src/ping_pong_client.rs b/benchmarks/ping-pong/app/src/ping_pong_client.rs index 523c84ae..49b47633 100644 --- a/benchmarks/ping-pong/app/src/ping_pong_client.rs +++ b/benchmarks/ping-pong/app/src/ping_pong_client.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct PingPongProgram; +impl PingPongProgram { + pub const ROUTE_ID_PING_PONG_SERVICE: u8 = 1; +} impl sails_rs::client::Program for PingPongProgram {} pub trait PingPong { type Env: sails_rs::client::GearEnv; @@ -14,7 +17,7 @@ impl PingPong for sails_rs::client::Actor sails_rs::client::Service { - self.service(stringify!(PingPongService)) + self.service(PingPongProgram::ROUTE_ID_PING_PONG_SERVICE) } } pub trait PingPongCtors { @@ -36,7 +39,7 @@ impl PingPongCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(NewForBench () -> ()); + sails_rs::io_struct_impl!(NewForBench () -> (), 0); } pub mod ping_pong_service { @@ -59,6 +62,10 @@ pub mod ping_pong_service { ) -> sails_rs::client::PendingCall; } pub struct PingPongServiceImpl; + impl sails_rs::client::Identifiable for PingPongServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([106, 114, 150, 138, 76, 98, 231, 215]); + } impl PingPongService for sails_rs::client::Service { @@ -73,6 +80,6 @@ pub mod ping_pong_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(Ping (payload: super::PingPongPayload) -> super::PingPongPayload); + sails_rs::io_struct_impl!(Ping (payload: super::PingPongPayload) -> super::PingPongPayload, 0, ::INTERFACE_ID); } } diff --git a/benchmarks/src/alloc_stress_program.rs b/benchmarks/src/alloc_stress_program.rs index 8413a96a..e65c6882 100644 --- a/benchmarks/src/alloc_stress_program.rs +++ b/benchmarks/src/alloc_stress_program.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct AllocStressProgram; +impl AllocStressProgram { + pub const ROUTE_ID_ALLOC_STRESS: u8 = 1; +} impl sails_rs::client::Program for AllocStressProgram {} pub trait AllocStress { type Env: sails_rs::client::GearEnv; @@ -10,7 +13,7 @@ pub trait AllocStress { impl AllocStress for sails_rs::client::Actor { type Env = E; fn alloc_stress(&self) -> sails_rs::client::Service { - self.service(stringify!(AllocStress)) + self.service(AllocStressProgram::ROUTE_ID_ALLOC_STRESS) } } pub trait AllocStressCtors { @@ -32,7 +35,7 @@ impl AllocStressCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(NewForBench () -> ()); + sails_rs::io_struct_impl!(NewForBench () -> (), 0); } pub mod alloc_stress { @@ -52,6 +55,10 @@ pub mod alloc_stress { ) -> sails_rs::client::PendingCall; } pub struct AllocStressImpl; + impl sails_rs::client::Identifiable for AllocStressImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([9, 48, 193, 195, 84, 117, 173, 52]); + } impl AllocStress for sails_rs::client::Service { type Env = E; fn alloc_stress( @@ -64,6 +71,6 @@ pub mod alloc_stress { pub mod io { use super::*; - sails_rs::io_struct_impl!(AllocStress (n: u32) -> super::AllocStressResult); + sails_rs::io_struct_impl!(AllocStress (n: u32) -> super::AllocStressResult, 0, ::INTERFACE_ID); } } diff --git a/benchmarks/src/benchmarks.rs b/benchmarks/src/benchmarks.rs index e9da1f80..ad75475f 100644 --- a/benchmarks/src/benchmarks.rs +++ b/benchmarks/src/benchmarks.rs @@ -18,15 +18,23 @@ //! ``` use crate::clients::{ - alloc_stress_client::{AllocStress as _, AllocStressCtors, alloc_stress::*}, - compute_stress_client::{ComputeStress as _, ComputeStressCtors, compute_stress::*}, - counter_bench_client::{CounterBench as _, CounterBenchCtors, counter_bench::*}, + alloc_stress_client::{ + AllocStress as _, AllocStressCtors, AllocStressProgram, alloc_stress::*, + }, + compute_stress_client::{ + ComputeStress as _, ComputeStressCtors, ComputeStressProgram, compute_stress::*, + }, + counter_bench_client::{ + CounterBench as _, CounterBenchCtors, CounterBenchProgram, counter_bench::*, + }, }; use gtest::{System, constants::DEFAULT_USER_ALICE}; use itertools::{Either, Itertools}; -use ping_pong_bench_app::client::{PingPong, PingPongCtors, ping_pong_service::*}; +use ping_pong_bench_app::client::{PingPong, PingPongCtors, PingPongProgram, ping_pong_service::*}; use redirect_client::{RedirectClient, RedirectClientCtors, redirect::*}; -use redirect_proxy_client::{RedirectProxyClient, RedirectProxyClientCtors, proxy::*}; +use redirect_proxy_client::{ + RedirectProxyClient, RedirectProxyClientCtors, RedirectProxyClientProgram, proxy::*, +}; use sails_rs::{client::*, prelude::*}; use std::{collections::BTreeMap, sync::atomic::AtomicU64}; @@ -67,11 +75,10 @@ async fn compute_stress_bench() { .map(|_| { let message_id = service.compute_stress(input_value).send_one_way().unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); - let stress_resp = crate::clients::compute_stress_client::compute_stress::io::ComputeStress::decode_reply_with_prefix( - "ComputeStress", - payload.as_slice(), - ) - .unwrap(); + // Low-level approach: decoding using generated io module + let stress_resp = + crate::clients::compute_stress_client::compute_stress::io::ComputeStress::decode_reply(ComputeStressProgram::ROUTE_ID_COMPUTE_STRESS, payload.as_slice()) + .unwrap(); assert_eq!(stress_resp.res, expected_sum); gas }) @@ -99,8 +106,9 @@ async fn counter_bench() { let gas = if is_sync { let message_id = service.inc().send_one_way().unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); - let stress_resp = crate::clients::counter_bench_client::counter_bench::io::Inc::decode_reply_with_prefix( - "CounterBench", + // Low-level approach: decoding using generated io module + let stress_resp = crate::clients::counter_bench_client::counter_bench::io::Inc::decode_reply( + CounterBenchProgram::ROUTE_ID_COUNTER_BENCH, payload.as_slice(), ) .unwrap(); @@ -111,8 +119,9 @@ async fn counter_bench() { } else { let message_id = service.inc_async().send_one_way().unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); - let stress_resp = crate::clients::counter_bench_client::counter_bench::io::IncAsync::decode_reply_with_prefix( - "CounterBench", + // Low-level approach: decoding using generated io module + let stress_resp = crate::clients::counter_bench_client::counter_bench::io::IncAsync::decode_reply( + CounterBenchProgram::ROUTE_ID_COUNTER_BENCH, payload.as_slice(), ) .unwrap(); @@ -158,9 +167,10 @@ async fn cross_program_bench() { .send_one_way() .unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); + // Low-level approach: decoding using generated io module let stress_resp = - ping_pong_bench_app::client::ping_pong_service::io::Ping::decode_reply_with_prefix( - "PingPongService", + ping_pong_bench_app::client::ping_pong_service::io::Ping::decode_reply( + PingPongProgram::ROUTE_ID_PING_PONG_SERVICE, payload.as_slice(), ) .unwrap(); @@ -199,8 +209,9 @@ async fn redirect_bench() { .send_one_way() .unwrap(); let (payload, _gas) = extract_reply_and_gas(env.system(), message_id); - let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply_with_prefix( - "Proxy", + // Low-level approach: decoding using generated io module + let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply( + RedirectProxyClientProgram::ROUTE_ID_PROXY, payload.as_slice(), ) .unwrap(); @@ -223,8 +234,9 @@ async fn redirect_bench() { .send_one_way() .unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); - let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply_with_prefix( - "Proxy", + // Low-level approach: decoding using generated io module + let resp = redirect_proxy_client::proxy::io::GetProgramId::decode_reply( + RedirectProxyClientProgram::ROUTE_ID_PROXY, payload.as_slice(), ) .unwrap(); @@ -269,11 +281,13 @@ async fn alloc_stress_test(n: u32) -> (usize, u64) { let mut service = program.alloc_stress(); let message_id = service.alloc_stress(n).send_one_way().unwrap(); let (payload, gas) = extract_reply_and_gas(env.system(), message_id); - let stress_resp = crate::clients::alloc_stress_client::alloc_stress::io::AllocStress::decode_reply_with_prefix( - "AllocStress", - payload.as_slice(), - ) - .unwrap(); + // Low-level approach: decoding using generated io module + let stress_resp = + crate::clients::alloc_stress_client::alloc_stress::io::AllocStress::decode_reply( + AllocStressProgram::ROUTE_ID_ALLOC_STRESS, + payload.as_slice(), + ) + .unwrap(); let expected_len = alloc_stress::fibonacci_sum(n) as usize; assert_eq!(stress_resp.inner.len(), expected_len); @@ -313,7 +327,7 @@ fn create_env() -> GtestEnv { async fn deploy_for_bench< P: Program, - IO: CallCodec, + IO: ServiceCall, F: FnOnce(Deployment) -> PendingCtor, >( env: &GtestEnv, @@ -326,7 +340,7 @@ async fn deploy_for_bench< async fn deploy_code_for_bench< P: Program, - IO: CallCodec, + IO: ServiceCall, F: FnOnce(Deployment) -> PendingCtor, >( env: &GtestEnv, diff --git a/benchmarks/src/compute_stress_program.rs b/benchmarks/src/compute_stress_program.rs index 0dab756e..72fc6c46 100644 --- a/benchmarks/src/compute_stress_program.rs +++ b/benchmarks/src/compute_stress_program.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct ComputeStressProgram; +impl ComputeStressProgram { + pub const ROUTE_ID_COMPUTE_STRESS: u8 = 1; +} impl sails_rs::client::Program for ComputeStressProgram {} pub trait ComputeStress { type Env: sails_rs::client::GearEnv; @@ -16,7 +19,7 @@ impl ComputeStress fn compute_stress( &self, ) -> sails_rs::client::Service { - self.service(stringify!(ComputeStress)) + self.service(ComputeStressProgram::ROUTE_ID_COMPUTE_STRESS) } } pub trait ComputeStressCtors { @@ -38,7 +41,7 @@ impl ComputeStressCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(NewForBench () -> ()); + sails_rs::io_struct_impl!(NewForBench () -> (), 0); } pub mod compute_stress { @@ -58,6 +61,10 @@ pub mod compute_stress { ) -> sails_rs::client::PendingCall; } pub struct ComputeStressImpl; + impl sails_rs::client::Identifiable for ComputeStressImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([254, 138, 70, 56, 122, 195, 121, 54]); + } impl ComputeStress for sails_rs::client::Service { @@ -72,6 +79,6 @@ pub mod compute_stress { pub mod io { use super::*; - sails_rs::io_struct_impl!(ComputeStress (n: u32) -> super::ComputeStressResult); + sails_rs::io_struct_impl!(ComputeStress (n: u32) -> super::ComputeStressResult, 0, ::INTERFACE_ID); } } diff --git a/benchmarks/src/counter_bench_program.rs b/benchmarks/src/counter_bench_program.rs index 50560441..46287d68 100644 --- a/benchmarks/src/counter_bench_program.rs +++ b/benchmarks/src/counter_bench_program.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct CounterBenchProgram; +impl CounterBenchProgram { + pub const ROUTE_ID_COUNTER_BENCH: u8 = 1; +} impl sails_rs::client::Program for CounterBenchProgram {} pub trait CounterBench { type Env: sails_rs::client::GearEnv; @@ -16,7 +19,7 @@ impl CounterBench fn counter_bench( &self, ) -> sails_rs::client::Service { - self.service(stringify!(CounterBench)) + self.service(CounterBenchProgram::ROUTE_ID_COUNTER_BENCH) } } pub trait CounterBenchCtors { @@ -38,7 +41,7 @@ impl CounterBenchCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(NewForBench () -> ()); + sails_rs::io_struct_impl!(NewForBench () -> (), 0); } pub mod counter_bench { @@ -49,6 +52,10 @@ pub mod counter_bench { fn inc_async(&mut self) -> sails_rs::client::PendingCall; } pub struct CounterBenchImpl; + impl sails_rs::client::Identifiable for CounterBenchImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([149, 170, 24, 82, 218, 19, 238, 13]); + } impl CounterBench for sails_rs::client::Service { type Env = E; fn inc(&mut self) -> sails_rs::client::PendingCall { @@ -61,7 +68,7 @@ pub mod counter_bench { pub mod io { use super::*; - sails_rs::io_struct_impl!(Inc () -> u64); - sails_rs::io_struct_impl!(IncAsync () -> u64); + sails_rs::io_struct_impl!(Inc () -> u64, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(IncAsync () -> u64, 1, ::INTERFACE_ID); } } diff --git a/rs/idl-meta/IDL_V2_SPEC.md b/docs/IDL_V2_SPEC.md similarity index 100% rename from rs/idl-meta/IDL_V2_SPEC.md rename to docs/IDL_V2_SPEC.md diff --git a/rs/reflect-hash/REFLECT_HASH_SPEC.md b/docs/REFLECT_HASH_SPEC.md similarity index 100% rename from rs/reflect-hash/REFLECT_HASH_SPEC.md rename to docs/REFLECT_HASH_SPEC.md diff --git a/docs/SAILS_HEADER_V1_SPEC.md b/docs/SAILS_HEADER_V1_SPEC.md new file mode 100644 index 00000000..ef3b9de1 --- /dev/null +++ b/docs/SAILS_HEADER_V1_SPEC.md @@ -0,0 +1,179 @@ +# Sails Header v1 Specification (Draft) + +## Abstract + +Sails Header defines a deterministic, userspace envelope for Sails-based Gear/Vara asynchronous messages. Every Sails message begins with a 16-byte base header (extensions optional) that encodes a magic prefix, version, payload offset, and three routing identifiers: a 64-bit `interface_id`, a 16-bit `entry_id`, and an 8-bit `route_idx`. The header lives entirely within the message payload, requiring no runtime or consensus changes, and enables off-chain tooling and cross-program interoperability by exposing canonical interface metadata. + +## Goals + +- **Interoperability.** Provide a uniform wire format so any program or tool can interpret interface- and entry-level information from the header alone. +- **Off-chain decodability.** Allow explorers, debuggers, and SDKs to decode Sails payloads without executing WASM by relying on the header’s identifiers. +- **Deterministic identifiers.** Tie `interface_id` and `entry_id` to the canonical interface definition so identical interfaces across languages receive identical IDs. +- **Compile-time embedding.** Make the identifiers available at compile time (e.g., via macros) so a program can embed routing data directly in the binary. +- **Backward compatibility.** Maintain the existing Gear message format; Sails Header occupies payload bytes only. + +### Non-Goals + +- Altering node runtime, consensus, or native message layout. +- Resurrecting deprecated metadata formats. + +## Terminology + +| Term | Meaning | +| ------------------- | ------------------------------------------------------------------------------------------------------------------ | +| Program | A deployed Sails program (Gear/Vara WASM module) with one or more interfaces. | +| Service / Interface | A logical API defined in IDL, consisting of functions and events. | +| Route | A named service instance. Programs may expose multiple instances per interface. | +| `interface_id` | 64-bit identifier derived from the interface hashing spec (service name excluded). | +| `entry_id` | 16-bit identifier for an interface entry (function/event), assigned deterministically. | +| `route_idx` | One-byte route index. `0x00` denotes the default instance. Non-zero indices are mapped via a per-program manifest. | + +## Header Layout + +``` +Byte offset Field Size (bytes) Description +0–1 Magic 2 ASCII "GM" (0x47 0x4D) +2 Version 1 Header version (0x01) +3 Header length 1 Total header size in bytes; base header = 0x10 +4–11 Interface ID 8 64-bit ID from Interface hash +12–13 Entry ID 2 Little-endian 16-bit entry identifier +14 Route Index 1 Unsigned byte; 0 = default route +15 Reserved 1 Must be set to 0x00 in v1 (no error flags). Future specs may repurpose this byte. +>15 Extensions variable Present only if `header length` > 0x10 +``` + +### Semantics + +- **Magic.** Indicates presence of Sails Header. Readers should verify `0x47 0x4D` before interpreting the remaining bytes. +- **Version.** Drives compatibility. Version 1 defines the format in this document; future versions may extend the header. +- **Header length.** Allows optional extensions to follow the base fields. Payload data starts at offset `header length`. +- **Interface ID.** Deterministic identifier computed via the hashing spec (see below). The ID never depends on the textual service name. +- **Entry ID.** Deterministically assigned `u16` per interface by sorting entry names lexicographically (ties resolved by canonical signature). Implementations may freeze the assignment in lockfiles to preserve wire compatibility. +- **Route Index.** Identifies which service instance is targeted; mapping from integer to route name is program-specific. +- **Reserved byte.** Always zero in v1 (no error flag semantics). Future revisions may reinterpret this byte. Receivers MUST treat non-zero values as invalid for v1 headers. +- **Extensions.** Optional, structured as a TLV stream (see below). `header length` MUST cover the base header plus all extension bytes. + +## Identifier Derivation + +### Interface ID + +See [REFLECT_HASH_SPEC](REFLECT_HASH_SPEC.md) + +### Entry ID + +**Commands and queries** + +1. Collect all commands and queries defined in the interface. +2. Sort by name (lexicographically). +3. Assign `entry_id` sequentially starting at zero. Implementations MAY pin these assignments externally (e.g., lockfile) if backwards compatibility is critical. + +**Events** + +1. Collect all events defined in the interface. +2. Sort by name (lexicographically). +3. Assign `entry_id` sequentially starting at zero. Implementations MAY pin these assignments externally (e.g., lockfile) if backwards compatibility is critical. + +### Route Index + +`route_idx` values are assigned by the program author. `0x00` is the default instance. Additional instances are mapped via a manifest or registry that downstream tooling can inspect. + +### Extension Framing (TBD) + +Extensions appear immediately after the base header (offset 16) and continue until `header length` bytes have been consumed. Each extension record uses a Tag-Length-Value format: + +``` +struct Extension { + type_id: u8; // 0 reserved + flags: u8; // extension-specific flags/version (0 if unused) + length: u16; // little-endian payload length in bytes + data: [u8; length]; +} +``` + +Parsing rules: + +1. Continue reading extensions until `header length` bytes are consumed. If no extension bytes are present, `header length` equals 0x10. +2. Each extension MUST fit entirely within `header length`; otherwise the header is invalid. +3. Unknown `type_id`s MUST be skipped using the declared `length`, ensuring forward compatibility. +4. `type_id = 0` is reserved and MUST NOT appear on the wire. +5. Implementations MAY standardize specific `type_id`s (e.g., correlation IDs) and document their payload structure separately. + +## Usage Requirements + +- Programs SHOULD compute `interface_id` and `entry_id` at compile time (e.g., using macros or IDL generators) and embed them as constants. This ensures routing does not depend on runtime hashing. +- When sending a message: + 1. Fill the 16-byte base header. + 2. Append any extensions (optional). + 3. Append the SCALE-encoded payload immediately after `header length`. +- Receivers MUST examine the magic + version to interpret the header. They MAY reject messages with unknown versions or with a header shorter than `0x10`. +- Off-chain tools (explorers, RPC gateways) can read the same header to classify messages without executing WASM. + +## Determinism Checklist + +Implementations MUST ensure: + +1. Service names never influence `interface_id`. +2. Ordering of extends/functions/events/types is stable (sort rules above). +3. `entry_id` assignment methodology is documented; ideally frozen via manifest for upgraded interfaces. + +## Validation Checklist + +A receiver that detects a potential header SHOULD apply at least the following checks: + +1. **Magic:** The first two bytes are `0x47 0x4D`; otherwise treat the payload as legacy/unheadered. +2. **Version:** `version == 0x01`. Unknown versions may be rejected or parsed according to future specs. +3. **Header length:** `hlen >= 0x10` and `hlen <= payload_length`. Reject if the length is smaller than the base header or extends beyond the payload. +4. **Reserved byte:** For v1 the byte at offset 15 MUST be zero. Non-zero values indicate incompatible behavior unless a future version redefines it. +5. **Extensions:** If `hlen > 0x10`, ensure each TLV record fits within the declared header length; malformed TLVs invalidate the header. + +Once the header passes validation, proceed to decode routing identifiers and payload. + +## Security Considerations + +- Headers with invalid magic, unsupported versions, non-zero reserved byte (in v1), or header lengths that extend beyond the payload MUST be rejected before processing. +- Extension parsing must respect `length` fields strictly; implementations SHOULD cap accepted header lengths to prevent resource exhaustion. +- Tooling should treat `interface_id`, `entry_id`, and `route_idx` as untrusted inputs - only use them after successful validation and cross-checking against known manifests. + +## Examples + +### Example A – Default Route Call + +Assume `interface_id = 0xA1B2C3D4E5F60718` and `entry_id = 0x0200` (`Foo::Bar`), default route (`route_idx = 0x00`), base header only. + +``` +47 4D 01 0B 18 07 F6 E5 D4 C3 B2 A1 02 00 00 00 +^magic ^ver ^hlen ^interface_id LE ^entry_id ^route ^reserved +``` + +Payload bytes follow immediately after byte offset 11. + +### Example B – Alternate Route (reserved byte zero) + +`interface_id = 0x0123456789ABCDEF`, `entry_id = 0x0500`, `route_idx = 0x02`, reserved byte remains zero. + +``` +47 4D 01 0B EF CD AB 89 67 45 23 01 05 00 02 00 +``` + +## Frequently Asked Questions + +**Q: How do I map `route_idx` back to route names?** +Provide a manifest that associates each route name with a 1-byte index. Tooling can distribute this manifest alongside the program binary or IDL. + +**Q: Can I include additional metadata in the header?** +Yes. Increase `header length` and append extension fields. Receivers that understand the extension can parse it; others should skip to `header length` before reading the payload. + +**Q: How do off-chain tools verify the header?** +Check the magic/version, read `interface_id` and `entry_id`, and consult a registry or IDL manifest to interpret the payload. + +## Normative References + +1. RFC 8785 - JavaScript Object Notation (JSON) Canonicalization Scheme. +2. BLAKE3 cryptographic hash function specification. +3. RFC 7914-style domain separation guidelines (domain-specific hashing). +4. SCALE Codec Specification – defines the serialization format used for the payload that follows the header. +5. Gear Protocol Documentation – describes the underlying asynchronous messaging context in which Sails Header operates. + +--- + +This document is intentionally implementation-neutral. Any language or framework can adopt the Sails Header provided it implements the canonical hashing rules and the binary layout defined above.\*\*\* diff --git a/examples/demo/app/src/lib.rs b/examples/demo/app/src/lib.rs index 922f2dde..434c0b0c 100644 --- a/examples/demo/app/src/lib.rs +++ b/examples/demo/app/src/lib.rs @@ -120,7 +120,7 @@ mod tests { let (data, value) = service_exposure.do_something_and_take_fee().to_tuple(); // Assert - assert_eq!("ValueFee".encode().as_slice(), service_exposure.route()); + assert_eq!(6, service_exposure.route_idx()); assert!(data); assert_eq!(value, message_value - 10_000_000_000_000); @@ -133,7 +133,7 @@ mod tests { let data = service_exposure.add(10); // Assert - assert_eq!("Counter".encode().as_slice(), service_exposure.route()); + assert_eq!(2, service_exposure.route_idx()); assert_eq!(52, data); let events = emitter.take_events(); assert_eq!(events.len(), 1); diff --git a/examples/demo/app/src/value_fee/mod.rs b/examples/demo/app/src/value_fee/mod.rs index e68800e0..48d244ce 100644 --- a/examples/demo/app/src/value_fee/mod.rs +++ b/examples/demo/app/src/value_fee/mod.rs @@ -53,7 +53,7 @@ mod tests { fn test_zero_value() { // Arrange: simulate call with zero transferred value. Syscall::with_message_value(0); - let mut fee_service = FeeService::new(100).expose(&[]); // fee = 100 + let mut fee_service = FeeService::new(100).expose(1); // fee = 100 // Act: invoke fee service. let (data, value) = fee_service.do_something_and_take_fee().to_tuple(); @@ -69,7 +69,7 @@ mod tests { // Arrange: simulate call with insufficient transferred value. Syscall::with_message_value(100); - let mut fee_service = FeeService::new(200).expose(&[]); // fee = 200 + let mut fee_service = FeeService::new(200).expose(1); // fee = 200 // Act: this should panic because transferred value < fee. let _ = fee_service.do_something_and_take_fee(); @@ -79,7 +79,7 @@ mod tests { fn test_fee_taken_with_zero_remaining() { // Arrange Syscall::with_message_value(100); - let mut fee_service = FeeService::new(100).expose(&[]); + let mut fee_service = FeeService::new(100).expose(1); // Act: fee is taken and remaining value is too small. let (data, value) = fee_service.do_something_and_take_fee().to_tuple(); @@ -96,7 +96,7 @@ mod tests { let message_value = 200 + Syscall::env_vars().existential_deposit; let fee = 100; Syscall::with_message_value(message_value); - let mut fee_service = FeeService::new(fee).expose(&[]); + let mut fee_service = FeeService::new(fee).expose(1); // Act: fee is taken and the remaining value is passed along. let (data, value) = fee_service.do_something_and_take_fee().to_tuple(); diff --git a/examples/demo/app/tests/gclient.rs b/examples/demo/app/tests/gclient.rs index 70e15336..c6f96d3e 100644 --- a/examples/demo/app/tests/gclient.rs +++ b/examples/demo/app/tests/gclient.rs @@ -112,7 +112,7 @@ async fn ping_pong_works() { // Use generated `io` module for encoding/decoding calls and replies // and send/receive bytes using `gclient` native means (env is just a wrapper) let ping_call_payload = - ping_pong::io::Ping::encode_params_with_prefix("PingPong", "ping".into()); + ping_pong::io::Ping::encode_call(DemoClientProgram::ROUTE_ID_PING_PONG, "ping".into()); // Act let ping_reply_payload = env @@ -124,8 +124,11 @@ async fn ping_pong_works() { .await .unwrap(); - let ping_reply = - ping_pong::io::Ping::decode_reply_with_prefix("PingPong", ping_reply_payload).unwrap(); + let ping_reply = ping_pong::io::Ping::decode_reply( + DemoClientProgram::ROUTE_ID_PING_PONG, + ping_reply_payload, + ) + .unwrap(); // Assert diff --git a/examples/demo/app/tests/gtest.rs b/examples/demo/app/tests/gtest.rs index d613e889..7f01bcf1 100644 --- a/examples/demo/app/tests/gtest.rs +++ b/examples/demo/app/tests/gtest.rs @@ -166,7 +166,7 @@ async fn ping_pong_low_level_works() { let demo_program = Program::from_file(&system, DEMO_WASM_PATH); // Use generated `io` module to create a program - let message_id = demo_program.send_bytes(ACTOR_ID, Default::encode_params()); + let message_id = demo_program.send_bytes(ACTOR_ID, Default::encode_params_with_header(0, &())); let run_result = system.run_next_block(); let gas_burned = *run_result .gas_burned @@ -177,7 +177,7 @@ async fn ping_pong_low_level_works() { // Use generated `io` module for encoding/decoding calls and replies // and send/receive bytes using `gtest` native means - let ping_call_payload = Ping::encode_params_with_prefix("PingPong", "ping".into()); + let ping_call_payload = Ping::encode_call(DemoClientProgram::ROUTE_ID_PING_PONG, "ping".into()); let message_id = demo_program.send_bytes(ACTOR_ID, ping_call_payload); let run_result = system.run_next_block(); @@ -190,7 +190,8 @@ async fn ping_pong_low_level_works() { let ping_reply_payload = reply_log_record.payload(); - let ping_reply = Ping::decode_reply_with_prefix("PingPong", ping_reply_payload).unwrap(); + let ping_reply = + Ping::decode_reply(DemoClientProgram::ROUTE_ID_PING_PONG, ping_reply_payload).unwrap(); assert_eq!(ping_reply, Ok("pong".to_string())); @@ -451,11 +452,11 @@ fn counter_add_low_level_works() { let wasm_size = std::fs::metadata(DEMO_WASM_PATH).unwrap().len(); // Use generated `io` module to create a program - demo_program.send_bytes(ACTOR_ID, Default::encode_params()); + let _message_id = demo_program.send_bytes(ACTOR_ID, Default::encode_params_with_header(0, &())); // Use generated `io` module for encoding/decoding calls and replies // and send/receive bytes using `gtest` native means - let call_payload = Add::encode_params_with_prefix("Counter", 10); + let call_payload = Add::encode_call(DemoClientProgram::ROUTE_ID_COUNTER, 10); let message_id = demo_program.send_bytes(ACTOR_ID, call_payload); let run_result = system.run_next_block(); @@ -468,7 +469,7 @@ fn counter_add_low_level_works() { let reply_payload = reply_log_record.payload(); - let reply = Add::decode_reply_with_prefix("Counter", reply_payload).unwrap(); + let reply = Add::decode_reply(DemoClientProgram::ROUTE_ID_COUNTER, reply_payload).unwrap(); assert_eq!(reply, 10); @@ -547,7 +548,7 @@ async fn program_value_transfer_works() { #[test] fn chaos_service_panic_after_wait_works() { - use demo_client::io::Default; + use demo_client::{chaos::io::PanicAfterWait, io::Default}; use gstd::errors::{ErrorReplyReason, SimpleExecutionError}; use sails_rs::gtest::{Log, Program, System}; @@ -555,9 +556,12 @@ fn chaos_service_panic_after_wait_works() { system.init_logger_with_default_filter("gwasm=debug,gtest=debug,sails_rs=debug"); system.mint_to(ACTOR_ID, 1_000_000_000_000_000); let program = Program::from_file(&system, DEMO_WASM_PATH); - program.send_bytes(ACTOR_ID, Default::encode_params()); + program.send_bytes(ACTOR_ID, Default::encode_params_with_header(0, &())); - let msg_id = program.send_bytes(ACTOR_ID, ("Chaos", "PanicAfterWait").encode()); + let msg_id = program.send_bytes( + ACTOR_ID, + PanicAfterWait::encode_call(DemoClientProgram::ROUTE_ID_CHAOS), + ); system.run_next_block(); let log = Log::builder().source(program.id()).dest(ACTOR_ID); @@ -577,17 +581,22 @@ fn chaos_service_panic_after_wait_works() { #[test] fn chaos_service_timeout_wait() { - use demo_client::chaos::io::ReplyHookCounter; - use demo_client::io::Default; + use demo_client::{ + chaos::io::{ReplyHookCounter, TimeoutWait}, + io::Default, + }; use sails_rs::gtest::{Log, Program, System}; let system = System::new(); system.init_logger_with_default_filter("gwasm=debug,gtest=info,sails_rs=debug,redirect=debug"); system.mint_to(ACTOR_ID, 1_000_000_000_000_000); let program = Program::from_file(&system, DEMO_WASM_PATH); - program.send_bytes(ACTOR_ID, Default::encode_params()); + program.send_bytes(ACTOR_ID, Default::encode_params_with_header(0, &())); - program.send_bytes(ACTOR_ID, ("Chaos", "TimeoutWait").encode()); + program.send_bytes( + ACTOR_ID, + TimeoutWait::encode_call(DemoClientProgram::ROUTE_ID_CHAOS), + ); //#1 system.run_next_block(); //#2 @@ -603,12 +612,15 @@ fn chaos_service_timeout_wait() { decode(payload) }; - let msg_id = program.send_bytes(ACTOR_ID, ("Chaos", "ReplyHookCounter").encode()); + let msg_id = program.send_bytes( + ACTOR_ID, + ReplyHookCounter::encode_call(DemoClientProgram::ROUTE_ID_CHAOS), + ); let run = system.run_next_block(); let val = extract_reply(&run, msg_id, |p| { - ReplyHookCounter::decode_reply_with_prefix("Chaos", p).unwrap() + ReplyHookCounter::decode_reply(DemoClientProgram::ROUTE_ID_CHAOS, p).unwrap() }); assert_eq!(val, 0, "handle_reply should not trigger before reply"); @@ -619,10 +631,13 @@ fn chaos_service_timeout_wait() { .unwrap(); system.run_next_block(); - let msg_id = program.send_bytes(ACTOR_ID, ("Chaos", "ReplyHookCounter").encode()); + let msg_id = program.send_bytes( + ACTOR_ID, + ReplyHookCounter::encode_call(DemoClientProgram::ROUTE_ID_CHAOS), + ); let run = system.run_next_block(); let val = extract_reply(&run, msg_id, |p| { - ReplyHookCounter::decode_reply_with_prefix("Chaos", p).unwrap() + ReplyHookCounter::decode_reply(DemoClientProgram::ROUTE_ID_CHAOS, p).unwrap() }); assert_eq!( val, 1, diff --git a/examples/demo/client/demo_client.idl b/examples/demo/client/demo_client.idl index c9745ec7..9f188c8f 100644 --- a/examples/demo/client/demo_client.idl +++ b/examples/demo/client/demo_client.idl @@ -1,9 +1,9 @@ !@sails: 0.9.2 -service PingPong@0x21bd9a9aa51da264 { +service PingPong@0x6d0eb40dde4038f7 { functions { - Ping(input: String) -> String throws String; + Ping(input: String) -> Result; } } @@ -60,13 +60,13 @@ service Dog@0x18666e67a21917a1 { } } -service References@0x3dab91b196478162 { +service References@0x8a0f8abe176d75b9 { functions { Add(v: u32) -> u32; AddByte(byte: u8) -> [u8]; - GuessNum(number: u8) -> String throws String; + GuessNum(number: u8) -> Result; Incr() -> ReferenceCount; - SetNum(number: u8) throws String; + SetNum(number: u8) -> Result<(), String>; @query Baked() -> String; @query @@ -79,13 +79,13 @@ service References@0x3dab91b196478162 { } } -service ThisThat@0x445bed6efbe8e6dd { +service ThisThat@0x381e13fdd02d675f { functions { - DoThat(param: DoThatParam) -> (ActorId, NonZeroU32, ManyVariantsReply) throws (String); + DoThat(param: DoThatParam) -> Result<(ActorId, NonZeroU32, ManyVariantsReply), (String)>; DoThis(p1: u32, p2: String, p3: (Option, NonZeroU8), p4: TupleStruct) -> (String, u32); Noop(); @query - That() -> String throws String; + That() -> Result; @query This() -> u32; } @@ -150,11 +150,11 @@ program DemoClient { New(counter: Option, dog_position: Option<(i32, i32)>); } services { - PingPong@0x21bd9a9aa51da264, + PingPong@0x6d0eb40dde4038f7, Counter@0x579d6daba41b7d82, Dog@0x18666e67a21917a1, - References@0x3dab91b196478162, - ThisThat@0x445bed6efbe8e6dd, + References@0x8a0f8abe176d75b9, + ThisThat@0x381e13fdd02d675f, ValueFee@0x41c1080b4e1e8dc5, Chaos@0xf0c8c80dfabf72d5, } diff --git a/examples/demo/client/src/demo_client.rs b/examples/demo/client/src/demo_client.rs index 5824ba91..19b55fb0 100644 --- a/examples/demo/client/src/demo_client.rs +++ b/examples/demo/client/src/demo_client.rs @@ -9,6 +9,15 @@ use core::num::NonZeroU32; #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct DemoClientProgram; +impl DemoClientProgram { + pub const ROUTE_ID_PING_PONG: u8 = 1; + pub const ROUTE_ID_COUNTER: u8 = 2; + pub const ROUTE_ID_DOG: u8 = 3; + pub const ROUTE_ID_REFERENCES: u8 = 4; + pub const ROUTE_ID_THIS_THAT: u8 = 5; + pub const ROUTE_ID_VALUE_FEE: u8 = 6; + pub const ROUTE_ID_CHAOS: u8 = 7; +} impl sails_rs::client::Program for DemoClientProgram {} pub trait DemoClient { type Env: sails_rs::client::GearEnv; @@ -23,25 +32,25 @@ pub trait DemoClient { impl DemoClient for sails_rs::client::Actor { type Env = E; fn ping_pong(&self) -> sails_rs::client::Service { - self.service(stringify!(PingPong)) + self.service(DemoClientProgram::ROUTE_ID_PING_PONG) } fn counter(&self) -> sails_rs::client::Service { - self.service(stringify!(Counter)) + self.service(DemoClientProgram::ROUTE_ID_COUNTER) } fn dog(&self) -> sails_rs::client::Service { - self.service(stringify!(Dog)) + self.service(DemoClientProgram::ROUTE_ID_DOG) } fn references(&self) -> sails_rs::client::Service { - self.service(stringify!(References)) + self.service(DemoClientProgram::ROUTE_ID_REFERENCES) } fn this_that(&self) -> sails_rs::client::Service { - self.service(stringify!(ThisThat)) + self.service(DemoClientProgram::ROUTE_ID_THIS_THAT) } fn value_fee(&self) -> sails_rs::client::Service { - self.service(stringify!(ValueFee)) + self.service(DemoClientProgram::ROUTE_ID_VALUE_FEE) } fn chaos(&self) -> sails_rs::client::Service { - self.service(stringify!(Chaos)) + self.service(DemoClientProgram::ROUTE_ID_CHAOS) } } pub trait DemoClientCtors { @@ -75,8 +84,8 @@ impl DemoClientCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(Default () -> ()); - sails_rs::io_struct_impl!(New (counter: super::Option, dog_position: super::Option<(i32, i32, ), >) -> ()); + sails_rs::io_struct_impl!(Default () -> (), 0); + sails_rs::io_struct_impl!(New (counter: super::Option, dog_position: super::Option<(i32, i32, ), >) -> (), 1); } pub mod ping_pong { @@ -86,6 +95,10 @@ pub mod ping_pong { fn ping(&mut self, input: String) -> sails_rs::client::PendingCall; } pub struct PingPongImpl; + impl sails_rs::client::Identifiable for PingPongImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([109, 14, 180, 13, 222, 64, 56, 247]); + } impl PingPong for sails_rs::client::Service { type Env = E; fn ping(&mut self, input: String) -> sails_rs::client::PendingCall { @@ -95,7 +108,7 @@ pub mod ping_pong { pub mod io { use super::*; - sails_rs::io_struct_impl!(Ping (input: String) -> super::Result); + sails_rs::io_struct_impl!(Ping (input: String) -> super::Result, 0, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -119,6 +132,10 @@ pub mod counter { fn value(&self) -> sails_rs::client::PendingCall; } pub struct CounterImpl; + impl sails_rs::client::Identifiable for CounterImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([87, 157, 109, 171, 164, 27, 125, 130]); + } impl Counter for sails_rs::client::Service { type Env = E; fn add(&mut self, value: u32) -> sails_rs::client::PendingCall { @@ -134,9 +151,9 @@ pub mod counter { pub mod io { use super::*; - sails_rs::io_struct_impl!(Add (value: u32) -> u32); - sails_rs::io_struct_impl!(Sub (value: u32) -> u32); - sails_rs::io_struct_impl!(Value () -> u32); + sails_rs::io_struct_impl!(Add (value: u32) -> u32, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Sub (value: u32) -> u32, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Value () -> u32, 2, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -147,12 +164,24 @@ pub mod counter { #[reflect_hash(crate = sails_rs)] pub enum CounterEvents { /// Emitted when a new value is added to the counter + #[codec(index = 0)] Added(u32), /// Emitted when a value is subtracted from the counter + #[codec(index = 1)] Subtracted(u32), } - impl sails_rs::client::Event for CounterEvents { - const EVENT_NAMES: &'static [Route] = &["Added", "Subtracted"]; + impl CounterEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Added { .. } => 0, + Self::Subtracted { .. } => 1, + } + } + } + impl sails_rs::client::Event for CounterEvents {} + impl sails_rs::client::Identifiable for CounterEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for CounterImpl { type Event = CounterEvents; @@ -176,6 +205,10 @@ pub mod walker_service { fn position(&self) -> sails_rs::client::PendingCall; } pub struct WalkerServiceImpl; + impl sails_rs::client::Identifiable for WalkerServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([238, 21, 54, 181, 81, 112, 191, 10]); + } impl WalkerService for sails_rs::client::Service { @@ -190,8 +223,8 @@ pub mod walker_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(Walk (dx: i32, dy: i32) -> ()); - sails_rs::io_struct_impl!(Position () -> (i32, i32, )); + sails_rs::io_struct_impl!(Walk (dx: i32, dy: i32) -> (), 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Position () -> (i32, i32, ), 1, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -201,10 +234,20 @@ pub mod walker_service { #[codec(crate = sails_rs::scale_codec)] #[reflect_hash(crate = sails_rs)] pub enum WalkerServiceEvents { + #[codec(index = 0)] Walked { from: (i32, i32), to: (i32, i32) }, } - impl sails_rs::client::Event for WalkerServiceEvents { - const EVENT_NAMES: &'static [Route] = &["Walked"]; + impl WalkerServiceEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Walked { .. } => 0, + } + } + } + impl sails_rs::client::Event for WalkerServiceEvents {} + impl sails_rs::client::Identifiable for WalkerServiceEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for WalkerServiceImpl { type Event = WalkerServiceEvents; @@ -228,6 +271,10 @@ pub mod mammal_service { fn avg_weight(&self) -> sails_rs::client::PendingCall; } pub struct MammalServiceImpl; + impl sails_rs::client::Identifiable for MammalServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([255, 107, 147, 225, 150, 16, 38, 254]); + } impl MammalService for sails_rs::client::Service { @@ -242,8 +289,8 @@ pub mod mammal_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(MakeSound () -> String); - sails_rs::io_struct_impl!(AvgWeight () -> u32); + sails_rs::io_struct_impl!(MakeSound () -> String, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(AvgWeight () -> u32, 1, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -268,6 +315,10 @@ pub mod dog { ) -> sails_rs::client::Service; } pub struct DogImpl; + impl sails_rs::client::Identifiable for DogImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([24, 102, 110, 103, 162, 25, 23, 161]); + } impl Dog for sails_rs::client::Service { type Env = E; fn make_sound(&mut self) -> sails_rs::client::PendingCall { @@ -289,7 +340,7 @@ pub mod dog { pub mod io { use super::*; - sails_rs::io_struct_impl!(MakeSound () -> String); + sails_rs::io_struct_impl!(MakeSound () -> String, 0, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -299,10 +350,20 @@ pub mod dog { #[codec(crate = sails_rs::scale_codec)] #[reflect_hash(crate = sails_rs)] pub enum DogEvents { + #[codec(index = 0)] Barked, } - impl sails_rs::client::Event for DogEvents { - const EVENT_NAMES: &'static [Route] = &["Barked"]; + impl DogEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Barked { .. } => 0, + } + } + } + impl sails_rs::client::Event for DogEvents {} + impl sails_rs::client::Identifiable for DogEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for DogImpl { type Event = DogEvents; @@ -340,6 +401,10 @@ pub mod references { fn message(&self) -> sails_rs::client::PendingCall; } pub struct ReferencesImpl; + impl sails_rs::client::Identifiable for ReferencesImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([138, 15, 138, 190, 23, 109, 117, 185]); + } impl References for sails_rs::client::Service { type Env = E; fn add(&mut self, v: u32) -> sails_rs::client::PendingCall { @@ -373,14 +438,14 @@ pub mod references { pub mod io { use super::*; - sails_rs::io_struct_impl!(Add (v: u32) -> u32); - sails_rs::io_struct_impl!(AddByte (byte: u8) -> Vec); - sails_rs::io_struct_impl!(GuessNum (number: u8) -> super::Result); - sails_rs::io_struct_impl!(Incr () -> super::ReferenceCount); - sails_rs::io_struct_impl!(SetNum (number: u8) -> super::Result<(), String>); - sails_rs::io_struct_impl!(Baked () -> String); - sails_rs::io_struct_impl!(LastByte () -> super::Option); - sails_rs::io_struct_impl!(Message () -> super::Option); + sails_rs::io_struct_impl!(Add (v: u32) -> u32, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(AddByte (byte: u8) -> Vec, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(GuessNum (number: u8) -> super::Result, 2, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Incr () -> super::ReferenceCount, 3, ::INTERFACE_ID); + sails_rs::io_struct_impl!(SetNum (number: u8) -> super::Result<(), String, >, 4, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Baked () -> String, 5, ::INTERFACE_ID); + sails_rs::io_struct_impl!(LastByte () -> super::Option, 6, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Message () -> super::Option, 7, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -450,6 +515,10 @@ pub mod this_that { fn this(&self) -> sails_rs::client::PendingCall; } pub struct ThisThatImpl; + impl sails_rs::client::Identifiable for ThisThatImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([56, 30, 19, 253, 208, 45, 103, 95]); + } impl ThisThat for sails_rs::client::Service { type Env = E; fn do_that( @@ -480,11 +549,11 @@ pub mod this_that { pub mod io { use super::*; - sails_rs::io_struct_impl!(DoThat (param: super::DoThatParam) -> super::Result<(ActorId, super::NonZeroU32, super::ManyVariantsReply, ), (String, )>); - sails_rs::io_struct_impl!(DoThis (p1: u32, p2: String, p3: (super::Option, super::NonZeroU8, ), p4: super::TupleStruct) -> (String, u32, )); - sails_rs::io_struct_impl!(Noop () -> ()); - sails_rs::io_struct_impl!(That () -> super::Result); - sails_rs::io_struct_impl!(This () -> u32); + sails_rs::io_struct_impl!(DoThat (param: super::DoThatParam) -> super::Result<(ActorId, super::NonZeroU32, super::ManyVariantsReply, ), (String, ), >, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(DoThis (p1: u32, p2: String, p3: (super::Option, super::NonZeroU8, ), p4: super::TupleStruct) -> (String, u32, ), 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Noop () -> (), 2, ::INTERFACE_ID); + sails_rs::io_struct_impl!(That () -> super::Result, 3, ::INTERFACE_ID); + sails_rs::io_struct_impl!(This () -> u32, 4, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -507,6 +576,10 @@ pub mod value_fee { ) -> sails_rs::client::PendingCall; } pub struct ValueFeeImpl; + impl sails_rs::client::Identifiable for ValueFeeImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([65, 193, 8, 11, 78, 30, 141, 197]); + } impl ValueFee for sails_rs::client::Service { type Env = E; fn do_something_and_take_fee( @@ -518,7 +591,7 @@ pub mod value_fee { pub mod io { use super::*; - sails_rs::io_struct_impl!(DoSomethingAndTakeFee () -> bool); + sails_rs::io_struct_impl!(DoSomethingAndTakeFee () -> bool, 0, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -528,10 +601,20 @@ pub mod value_fee { #[codec(crate = sails_rs::scale_codec)] #[reflect_hash(crate = sails_rs)] pub enum ValueFeeEvents { + #[codec(index = 0)] Withheld(u128), } - impl sails_rs::client::Event for ValueFeeEvents { - const EVENT_NAMES: &'static [Route] = &["Withheld"]; + impl ValueFeeEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Withheld { .. } => 0, + } + } + } + impl sails_rs::client::Event for ValueFeeEvents {} + impl sails_rs::client::Identifiable for ValueFeeEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for ValueFeeImpl { type Event = ValueFeeEvents; @@ -558,6 +641,10 @@ pub mod chaos { fn timeout_wait(&self) -> sails_rs::client::PendingCall; } pub struct ChaosImpl; + impl sails_rs::client::Identifiable for ChaosImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([240, 200, 200, 13, 250, 191, 114, 213]); + } impl Chaos for sails_rs::client::Service { type Env = E; fn panic_after_wait(&self) -> sails_rs::client::PendingCall { @@ -575,9 +662,9 @@ pub mod chaos { pub mod io { use super::*; - sails_rs::io_struct_impl!(PanicAfterWait () -> ()); - sails_rs::io_struct_impl!(ReplyHookCounter () -> u32); - sails_rs::io_struct_impl!(TimeoutWait () -> ()); + sails_rs::io_struct_impl!(PanicAfterWait () -> (), 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(ReplyHookCounter () -> u32, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(TimeoutWait () -> (), 2, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/examples/demo/client/src/lib.rs b/examples/demo/client/src/lib.rs index bc81cfaf..596246fe 100644 --- a/examples/demo/client/src/lib.rs +++ b/examples/demo/client/src/lib.rs @@ -11,8 +11,10 @@ mod tests { fn test_io_module_encode() { use this_that::*; - let bytes = io::DoThat::encode_params_with_prefix( - "ThisThat", + // Use the new simplified encode_call method + // It automatically uses the InterfaceId from the service module + let bytes = io::DoThat::encode_call( + DemoClientProgram::ROUTE_ID_THIS_THAT, DoThatParam { p1: NonZeroU32::MAX, p2: 123.into(), @@ -20,35 +22,46 @@ mod tests { }, ); - assert_eq!( - bytes, - vec![ - 32, 84, 104, 105, 115, 84, 104, 97, 116, // ThisThat - 24, 68, 111, 84, 104, 97, 116, // DoThat - 255, 255, 255, 255, // p1 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, // p2 - 0, // p3 - ] - ); + let mut expected = vec![ + 0x47, 0x4D, 0x01, 0x10, // Magic, Version, Header Length + 56, 30, 19, 253, 208, 45, 103, 95, // Interface ID + 0, 0, // Entry ID + 5, // Route Index + 0, // Reserved + ]; + expected.extend_from_slice(&[ + 255, 255, 255, 255, // p1 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, // p2 + 0, // p3 + ]); + + assert_eq!(bytes, expected); } #[test] fn test_io_module_decode_reply() { use this_that::*; - let bytes = vec![ - 32, 84, 104, 105, 115, 84, 104, 97, 116, // ThisThat - 24, 68, 111, 84, 104, 97, 116, // DoThat - 0, // Ok + // We don't need manual InterfaceId anymore, it's inside decode_reply + let mut bytes = vec![ + 0x47, 0x4D, 0x01, 0x10, // Magic, Version, Header Length + 56, 30, 19, 253, 208, 45, 103, 95, // Interface ID + 0, 0, // Entry ID + 0, // Route Index + 0, // Reserved + ]; + bytes.extend_from_slice(&[ + 0, // Ok 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 123 255, 255, 255, 255, // NonZeroU32::MAX 0, // ManyVariantsReply::One - ]; + ]); + // Use the simplified method let reply: Result<(ActorId, NonZeroU32, ManyVariantsReply), (String,)> = - io::DoThat::decode_reply_with_prefix("ThisThat", bytes).unwrap(); + io::DoThat::decode_reply(0, bytes).unwrap(); assert_eq!( reply, diff --git a/examples/event-routes/app/src/lib.rs b/examples/event-routes/app/src/lib.rs index 57a00fb6..7ec279ec 100644 --- a/examples/event-routes/app/src/lib.rs +++ b/examples/event-routes/app/src/lib.rs @@ -1,6 +1,10 @@ #![no_std] -use sails_rs::{gstd, prelude::*}; +use sails_rs::{ + gstd, + meta::{InterfaceId, ServiceMeta}, + prelude::*, +}; #[event] #[derive(Clone, Debug, PartialEq, Encode, TypeInfo, ReflectHash)] @@ -62,3 +66,5 @@ pub use code::WASM_BINARY_OPT as WASM_BINARY; mod code { include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); } + +pub const INTERFACE_ID: InterfaceId = ::INTERFACE_ID; diff --git a/examples/event-routes/tests/gtest.rs b/examples/event-routes/tests/gtest.rs index 946eb207..e33d8ab9 100644 --- a/examples/event-routes/tests/gtest.rs +++ b/examples/event-routes/tests/gtest.rs @@ -1,5 +1,8 @@ use gtest::{Log, Program, System}; -use sails_rs::Encode; +use sails_rs::{ + Encode, + meta::{InterfaceId, SailsMessageHeader}, +}; const ACTOR_ID: u64 = 42; @@ -15,29 +18,35 @@ async fn event_routes_work() { let program = Program::from_binary_with_id(&system, program_id, event_routes_app::WASM_BINARY); // Send init message - _ = program.send_bytes(ACTOR_ID, ("New",).encode()); + let header = SailsMessageHeader::v1(InterfaceId::zero(), 0, 0); + _ = program.send_bytes(ACTOR_ID, header.encode()); _ = system.run_next_block(); // Send messages to services `Foo` and `Bar` to start `Foo` - program.send_bytes(ACTOR_ID, ("Foo", "Foo").encode()); - program.send_bytes(ACTOR_ID, ("Bar", "Foo").encode()); + let header_foo = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 0, 1); + program.send_bytes(ACTOR_ID, header_foo.encode()); + let header_bar = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 0, 2); + program.send_bytes(ACTOR_ID, header_bar.encode()); let run_result = system.run_next_block(); // Ensure that both `Foo` and `Bar` have been started + let header_foo_start = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 1, 1); let log_foo_start = Log::builder() .source(program_id) .dest(0) - .payload_bytes(("Foo", "Start").encode()); + .payload_bytes(header_foo_start.encode()); + + let header_bar_start = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 1, 2); let log_bar_start = Log::builder() .source(program_id) .dest(0) - .payload_bytes(("Bar", "Start").encode()); + .payload_bytes(header_bar_start.encode()); assert!(run_result.contains(&log_foo_start)); assert!(run_result.contains(&log_bar_start)); - // Send reply to message from `Foo` service + // // Send reply to message from `Foo` service let log = Log::builder().dest(ACTOR_ID).payload_bytes((1u8).encode()); let _reply_id = system .get_mailbox(ACTOR_ID) @@ -47,10 +56,11 @@ async fn event_routes_work() { let run_result = system.run_next_block(); // Ensure that `Foo` has been ended + let header_foo_end = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 0, 1); let log_foo_end = Log::builder() .source(program_id) .dest(0) - .payload_bytes(("Foo", "End").encode()); + .payload_bytes(header_foo_end.encode()); assert!(run_result.contains(&log_foo_end)); // Send reply to message from `Foo` service @@ -63,9 +73,10 @@ async fn event_routes_work() { let run_result = system.run_next_block(); // Ensure that `Bar` has been ended + let header_bar_end = SailsMessageHeader::v1(event_routes_app::INTERFACE_ID, 0, 2); let log_bar_end = Log::builder() .source(program_id) .dest(0) - .payload_bytes(("Bar", "End").encode()); + .payload_bytes(header_bar_end.encode()); assert!(run_result.contains(&log_bar_end)); } diff --git a/examples/no-svcs-prog/wasm/src/no_svcs_prog.rs b/examples/no-svcs-prog/wasm/src/no_svcs_prog.rs index 6c09a717..b85ac55f 100644 --- a/examples/no-svcs-prog/wasm/src/no_svcs_prog.rs +++ b/examples/no-svcs-prog/wasm/src/no_svcs_prog.rs @@ -2,6 +2,7 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct NoSvcsProgProgram; +impl NoSvcsProgProgram {} impl sails_rs::client::Program for NoSvcsProgProgram {} pub trait NoSvcsProg { type Env: sails_rs::client::GearEnv; @@ -24,5 +25,5 @@ impl NoSvcsProgCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(Create () -> ()); + sails_rs::io_struct_impl!(Create () -> (), 0); } diff --git a/examples/ping-pong-stack/Cargo.toml b/examples/ping-pong-stack/Cargo.toml index aecf51bd..64a3889f 100644 --- a/examples/ping-pong-stack/Cargo.toml +++ b/examples/ping-pong-stack/Cargo.toml @@ -10,5 +10,5 @@ sails-rs.workspace = true sails-rs = { workspace = true, features = ["build"] } [dev-dependencies] -sails-rs = { workspace = true, features = ["gtest"] } +sails-rs = { workspace = true, features = ["gtest", "debug"] } tokio = { workspace = true, features = ["rt", "macros"] } diff --git a/examples/ping-pong-stack/src/lib.rs b/examples/ping-pong-stack/src/lib.rs index 32777cb2..1a01072d 100644 --- a/examples/ping-pong-stack/src/lib.rs +++ b/examples/ping-pong-stack/src/lib.rs @@ -4,7 +4,7 @@ use client::{ PingPongStack as _, PingPongStackCtors as _, PingPongStackProgram, ping_pong_stack::PingPongStack as _, }; -use sails_rs::{client::Program as _, gstd::*, prelude::*}; +use sails_rs::{client::Program as _, gstd::*, meta::ServiceMeta, prelude::*}; struct PingPongStack(ActorId); @@ -81,3 +81,5 @@ pub use code::WASM_BINARY_OPT as WASM_BINARY; mod code { include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); } + +pub const INTERFACE_ID: sails_rs::meta::InterfaceId = PingPongStack::INTERFACE_ID; diff --git a/examples/ping-pong-stack/src/ping_pong_stack.rs b/examples/ping-pong-stack/src/ping_pong_stack.rs index 19a4ea4a..652595bc 100644 --- a/examples/ping-pong-stack/src/ping_pong_stack.rs +++ b/examples/ping-pong-stack/src/ping_pong_stack.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct PingPongStackProgram; +impl PingPongStackProgram { + pub const ROUTE_ID_PING_PONG_STACK: u8 = 1; +} impl sails_rs::client::Program for PingPongStackProgram {} pub trait PingPongStack { type Env: sails_rs::client::GearEnv; @@ -16,7 +19,7 @@ impl PingPongStack fn ping_pong_stack( &self, ) -> sails_rs::client::Service { - self.service(stringify!(PingPongStack)) + self.service(PingPongStackProgram::ROUTE_ID_PING_PONG_STACK) } } pub trait PingPongStackCtors { @@ -48,8 +51,8 @@ impl PingPongStackCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(CreatePing (code_id: CodeId) -> ()); - sails_rs::io_struct_impl!(CreatePong () -> ()); + sails_rs::io_struct_impl!(CreatePing (code_id: CodeId) -> (), 0); + sails_rs::io_struct_impl!(CreatePong () -> (), 1); } pub mod ping_pong_stack { @@ -60,6 +63,10 @@ pub mod ping_pong_stack { fn start(&mut self, limit: u32) -> sails_rs::client::PendingCall; } pub struct PingPongStackImpl; + impl sails_rs::client::Identifiable for PingPongStackImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([48, 181, 231, 61, 179, 133, 133, 236]); + } impl PingPongStack for sails_rs::client::Service { @@ -74,7 +81,7 @@ pub mod ping_pong_stack { pub mod io { use super::*; - sails_rs::io_struct_impl!(Ping (countdown: u32) -> ()); - sails_rs::io_struct_impl!(Start (limit: u32) -> ()); + sails_rs::io_struct_impl!(Ping (countdown: u32) -> (), 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Start (limit: u32) -> (), 1, ::INTERFACE_ID); } } diff --git a/examples/ping-pong-stack/tests/gtest.rs b/examples/ping-pong-stack/tests/gtest.rs index 4213368a..7323dbea 100644 --- a/examples/ping-pong-stack/tests/gtest.rs +++ b/examples/ping-pong-stack/tests/gtest.rs @@ -7,6 +7,10 @@ const ACTOR_ID: u64 = 42; #[tokio::test] async fn ping_pong_stack_works() { + assert_eq!( + ping_pong_stack::INTERFACE_ID, + ping_pong_stack::client::ping_pong_stack::PingPongStackImpl::INTERFACE_ID + ); let (env, code_id, _gas_limit) = create_env(); let program = env diff --git a/examples/proxy/src/this_that/mod.rs b/examples/proxy/src/this_that/mod.rs index 567d723e..e66232f1 100644 --- a/examples/proxy/src/this_that/mod.rs +++ b/examples/proxy/src/this_that/mod.rs @@ -1,8 +1,11 @@ -use demo_client::{this_that::ThisThat, this_that::*}; +use demo_client::{ + this_that::*, + this_that::{ThisThat, ThisThatImpl}, +}; use sails_rename::{client::*, gstd::Syscall, prelude::*}; #[derive(Clone)] -pub struct ThisThatCaller { +pub struct ThisThatCaller> { this_that: ThisThatClient, } impl ThisThatCaller @@ -63,7 +66,7 @@ mod tests { .returning(|| PendingCall::from_output(42)); // act - let this_that_caller = ThisThatCaller::new(mock_this_that).expose(&[]); + let this_that_caller = ThisThatCaller::new(mock_this_that).expose(1); let resp = this_that_caller.query_this(ACTOR_ID.into()).await; // assert @@ -82,7 +85,7 @@ mod tests { .returning(move |p1, p2, _p3, _p4| PendingCall::from_output((p2.clone(), p1))); // act - let mut this_that_caller = ThisThatCaller::new(mock_this_that).expose(&[]); + let mut this_that_caller = ThisThatCaller::new(mock_this_that).expose(1); let resp = this_that_caller .call_do_this( 42, @@ -107,7 +110,7 @@ mod tests { let mock_this_that = MockThisThat::new(); // act - let mut this_that_caller = ThisThatCaller::new(mock_this_that).expose(&[]); + let mut this_that_caller = ThisThatCaller::new(mock_this_that).expose(1); _ = this_that_caller .call_do_this( 42, diff --git a/examples/redirect/client/src/redirect_client.rs b/examples/redirect/client/src/redirect_client.rs index 186b1231..7d4885d7 100644 --- a/examples/redirect/client/src/redirect_client.rs +++ b/examples/redirect/client/src/redirect_client.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct RedirectClientProgram; +impl RedirectClientProgram { + pub const ROUTE_ID_REDIRECT: u8 = 1; +} impl sails_rs::client::Program for RedirectClientProgram {} pub trait RedirectClient { type Env: sails_rs::client::GearEnv; @@ -12,7 +15,7 @@ impl RedirectClient { type Env = E; fn redirect(&self) -> sails_rs::client::Service { - self.service(stringify!(Redirect)) + self.service(RedirectClientProgram::ROUTE_ID_REDIRECT) } } pub trait RedirectClientCtors { @@ -32,7 +35,7 @@ impl RedirectClientCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(New () -> ()); + sails_rs::io_struct_impl!(New () -> (), 0); } pub mod redirect { @@ -48,6 +51,10 @@ pub mod redirect { fn get_program_id(&self) -> sails_rs::client::PendingCall; } pub struct RedirectImpl; + impl sails_rs::client::Identifiable for RedirectImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([186, 88, 222, 225, 203, 117, 81, 30]); + } impl Redirect for sails_rs::client::Service { type Env = E; fn exit( @@ -63,7 +70,7 @@ pub mod redirect { pub mod io { use super::*; - sails_rs::io_struct_impl!(Exit (inheritor_id: ActorId) -> ()); - sails_rs::io_struct_impl!(GetProgramId () -> ActorId); + sails_rs::io_struct_impl!(Exit (inheritor_id: ActorId) -> (), 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(GetProgramId () -> ActorId, 1, ::INTERFACE_ID); } } diff --git a/examples/redirect/proxy-client/src/redirect_proxy_client.rs b/examples/redirect/proxy-client/src/redirect_proxy_client.rs index c880a754..7b7efd04 100644 --- a/examples/redirect/proxy-client/src/redirect_proxy_client.rs +++ b/examples/redirect/proxy-client/src/redirect_proxy_client.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct RedirectProxyClientProgram; +impl RedirectProxyClientProgram { + pub const ROUTE_ID_PROXY: u8 = 1; +} impl sails_rs::client::Program for RedirectProxyClientProgram {} pub trait RedirectProxyClient { type Env: sails_rs::client::GearEnv; @@ -12,7 +15,7 @@ impl RedirectProxyClient { type Env = E; fn proxy(&self) -> sails_rs::client::Service { - self.service(stringify!(Proxy)) + self.service(RedirectProxyClientProgram::ROUTE_ID_PROXY) } } pub trait RedirectProxyClientCtors { @@ -39,7 +42,7 @@ impl RedirectProxyClientCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(New (target: ActorId) -> ()); + sails_rs::io_struct_impl!(New (target: ActorId) -> (), 0); } pub mod proxy { @@ -50,6 +53,10 @@ pub mod proxy { fn get_program_id(&self) -> sails_rs::client::PendingCall; } pub struct ProxyImpl; + impl sails_rs::client::Identifiable for ProxyImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([115, 132, 52, 118, 255, 19, 124, 126]); + } impl Proxy for sails_rs::client::Service { type Env = E; fn get_program_id(&self) -> sails_rs::client::PendingCall { @@ -59,6 +66,6 @@ pub mod proxy { pub mod io { use super::*; - sails_rs::io_struct_impl!(GetProgramId () -> ActorId); + sails_rs::io_struct_impl!(GetProgramId () -> ActorId, 0, ::INTERFACE_ID); } } diff --git a/examples/rmrk/catalog/wasm/Cargo.toml b/examples/rmrk/catalog/wasm/Cargo.toml index b811658e..88156ed0 100644 --- a/examples/rmrk/catalog/wasm/Cargo.toml +++ b/examples/rmrk/catalog/wasm/Cargo.toml @@ -9,5 +9,5 @@ rmrk-catalog-app = { path = "../app" } [build-dependencies] # TODO: Switch to new IDL generator crate # sails-idl-gen.workspace = true -sails-rs = { workspace = true, features = ["wasm-builder"] } +sails-rs = { workspace = true, features = ["build"] } rmrk-catalog-app = { path = "../app" } # Used for generating IDL (service metadata) diff --git a/examples/rmrk/catalog/wasm/build.rs b/examples/rmrk/catalog/wasm/build.rs index 045f5ce3..886dcc0d 100644 --- a/examples/rmrk/catalog/wasm/build.rs +++ b/examples/rmrk/catalog/wasm/build.rs @@ -1,11 +1,11 @@ -// use rmrk_catalog_app::Program; -// use std::{env, path::PathBuf}; +use std::{env, path::PathBuf}; fn main() { sails_rs::build_wasm(); - // sails_idl_gen::generate_idl_to_file::( - // PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("rmrk-catalog.idl"), - // ) - // .unwrap(); + sails_rs::generate_idl_to_file::( + Some("RmrkCatalog"), + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("rmrk-catalog.idl"), + ) + .unwrap(); } diff --git a/examples/rmrk/catalog/wasm/rmrk-catalog.idl b/examples/rmrk/catalog/wasm/rmrk-catalog.idl index 1932654f..64253e48 100644 --- a/examples/rmrk/catalog/wasm/rmrk-catalog.idl +++ b/examples/rmrk/catalog/wasm/rmrk-catalog.idl @@ -1,16 +1,16 @@ !@sails: 0.9.2 -service RmrkCatalog { +service RmrkCatalog@0x37e91447bb13ed3c { functions { - AddEquippables(part_id: u32, collection_ids: [ActorId]) -> (u32, [ActorId]) throws Error; - AddParts(parts: [(u32, Part)]) -> [(u32, Part)] throws Error; - RemoveEquippable(part_id: u32, collection_id: ActorId) -> (u32, ActorId) throws Error; - RemoveParts(part_ids: [u32]) -> [u32] throws Error; - ResetEquippables(part_id: u32) throws Error; - SetEquippablesToAll(part_id: u32) throws Error; + AddEquippables(part_id: u32, collection_ids: [ActorId]) -> Result<(u32, [ActorId]), Error>; + AddParts(parts: [(u32, Part)]) -> Result<[(u32, Part)], Error>; + RemoveEquippable(part_id: u32, collection_id: ActorId) -> Result<(u32, ActorId), Error>; + RemoveParts(part_ids: [u32]) -> Result<[u32], Error>; + ResetEquippables(part_id: u32) -> Result<(), Error>; + SetEquippablesToAll(part_id: u32) -> Result<(), Error>; @query - Equippable(part_id: u32, collection_id: ActorId) -> bool throws Error; + Equippable(part_id: u32, collection_id: ActorId) -> Result; @query Part(part_id: u32) -> Option; } @@ -54,6 +54,6 @@ program RmrkCatalog { New(); } services { - RmrkCatalog, + RmrkCatalog@0x37e91447bb13ed3c, } } diff --git a/examples/rmrk/resource/app/src/rmrk_catalog.rs b/examples/rmrk/resource/app/src/rmrk_catalog.rs index fc847ad8..3f48060f 100644 --- a/examples/rmrk/resource/app/src/rmrk_catalog.rs +++ b/examples/rmrk/resource/app/src/rmrk_catalog.rs @@ -5,6 +5,9 @@ extern crate std; #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct RmrkCatalogProgram; +impl RmrkCatalogProgram { + pub const ROUTE_ID_RMRK_CATALOG: u8 = 1; +} impl sails_rs::client::Program for RmrkCatalogProgram {} pub trait RmrkCatalog { type Env: sails_rs::client::GearEnv; @@ -13,7 +16,7 @@ pub trait RmrkCatalog { impl RmrkCatalog for sails_rs::client::Actor { type Env = E; fn rmrk_catalog(&self) -> sails_rs::client::Service { - self.service(stringify!(RmrkCatalog)) + self.service(RmrkCatalogProgram::ROUTE_ID_RMRK_CATALOG) } } pub trait RmrkCatalogCtors { @@ -33,7 +36,7 @@ impl RmrkCatalogCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(New () -> ()); + sails_rs::io_struct_impl!(New () -> (), 0); } pub mod rmrk_catalog { @@ -121,6 +124,10 @@ pub mod rmrk_catalog { fn part(&self, part_id: u32) -> sails_rs::client::PendingCall; } pub struct RmrkCatalogImpl; + impl sails_rs::client::Identifiable for RmrkCatalogImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([55, 233, 20, 71, 187, 19, 237, 60]); + } impl RmrkCatalog for sails_rs::client::Service { type Env = E; fn add_equippables( @@ -175,14 +182,14 @@ pub mod rmrk_catalog { pub mod io { use super::*; - sails_rs::io_struct_impl!(AddEquippables (part_id: u32, collection_ids: Vec) -> super::Result<(u32, Vec, ), super::Error>); - sails_rs::io_struct_impl!(AddParts (parts: Vec<(u32, super::Part, )>) -> super::Result, super::Error>); - sails_rs::io_struct_impl!(RemoveEquippable (part_id: u32, collection_id: ActorId) -> super::Result<(u32, ActorId, ), super::Error>); - sails_rs::io_struct_impl!(RemoveParts (part_ids: Vec) -> super::Result, super::Error>); - sails_rs::io_struct_impl!(ResetEquippables (part_id: u32) -> super::Result<(), super::Error>); - sails_rs::io_struct_impl!(SetEquippablesToAll (part_id: u32) -> super::Result<(), super::Error>); - sails_rs::io_struct_impl!(Equippable (part_id: u32, collection_id: ActorId) -> super::Result); - sails_rs::io_struct_impl!(Part (part_id: u32) -> super::Option); + sails_rs::io_struct_impl!(AddEquippables (part_id: u32, collection_ids: Vec) -> super::Result<(u32, Vec, ), super::Error, >, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(AddParts (parts: Vec<(u32, super::Part, )>) -> super::Result, super::Error, >, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(RemoveEquippable (part_id: u32, collection_id: ActorId) -> super::Result<(u32, ActorId, ), super::Error, >, 2, ::INTERFACE_ID); + sails_rs::io_struct_impl!(RemoveParts (part_ids: Vec) -> super::Result, super::Error, >, 3, ::INTERFACE_ID); + sails_rs::io_struct_impl!(ResetEquippables (part_id: u32) -> super::Result<(), super::Error, >, 4, ::INTERFACE_ID); + sails_rs::io_struct_impl!(SetEquippablesToAll (part_id: u32) -> super::Result<(), super::Error, >, 5, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Equippable (part_id: u32, collection_id: ActorId) -> super::Result, 6, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Part (part_id: u32) -> super::Option, 7, ::INTERFACE_ID); } #[cfg(feature = "mockall")] diff --git a/examples/rmrk/resource/app/src/services/mod.rs b/examples/rmrk/resource/app/src/services/mod.rs index e58ae4dd..9f8c8012 100644 --- a/examples/rmrk/resource/app/src/services/mod.rs +++ b/examples/rmrk/resource/app/src/services/mod.rs @@ -1,4 +1,4 @@ -use crate::catalogs::rmrk_catalog::RmrkCatalog; +use crate::catalogs::rmrk_catalog::{RmrkCatalog, RmrkCatalogImpl}; use errors::{Error, Result}; use resources::{ComposedResource, PartId, Resource, ResourceId}; use sails_rs::{ @@ -36,7 +36,7 @@ pub enum ResourceStorageEvent { }, } -pub struct ResourceStorage { +pub struct ResourceStorage> { catalog_client: TCatalogClient, } @@ -189,7 +189,7 @@ mod tests { Syscall::with_message_source(ActorId::from(1)); ResourceStorage::::seed(); - let mut resource_storage = ResourceStorage::new(MockRmrkCatalog::new()).expose(&[]); + let mut resource_storage = ResourceStorage::new(MockRmrkCatalog::new()).expose(1); let resource = Resource::Composed(ComposedResource { src: "src".to_string(), diff --git a/examples/rmrk/resource/wasm/src/rmrk_resource.rs b/examples/rmrk/resource/wasm/src/rmrk_resource.rs index a221a716..e2ffda17 100644 --- a/examples/rmrk/resource/wasm/src/rmrk_resource.rs +++ b/examples/rmrk/resource/wasm/src/rmrk_resource.rs @@ -2,6 +2,9 @@ #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct RmrkResourceProgram; +impl RmrkResourceProgram { + pub const ROUTE_ID_RMRK_RESOURCE: u8 = 1; +} impl sails_rs::client::Program for RmrkResourceProgram {} pub trait RmrkResource { type Env: sails_rs::client::GearEnv; @@ -16,7 +19,7 @@ impl RmrkResource fn rmrk_resource( &self, ) -> sails_rs::client::Service { - self.service(stringify!(RmrkResource)) + self.service(RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE) } } pub trait RmrkResourceCtors { @@ -36,7 +39,7 @@ impl RmrkResourceCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(New () -> ()); + sails_rs::io_struct_impl!(New () -> (), 0); } pub mod rmrk_resource { @@ -124,6 +127,10 @@ pub mod rmrk_resource { ) -> sails_rs::client::PendingCall; } pub struct RmrkResourceImpl; + impl sails_rs::client::Identifiable for RmrkResourceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([215, 56, 96, 51, 70, 205, 63, 27]); + } impl RmrkResource for sails_rs::client::Service { type Env = E; fn add_part_to_resource( @@ -150,9 +157,9 @@ pub mod rmrk_resource { pub mod io { use super::*; - sails_rs::io_struct_impl!(AddPartToResource (resource_id: u8, part_id: u32) -> super::Result); - sails_rs::io_struct_impl!(AddResourceEntry (resource_id: u8, resource: super::Resource) -> super::Result<(u8, super::Resource, ), super::Error, >); - sails_rs::io_struct_impl!(Resource (resource_id: u8) -> super::Result); + sails_rs::io_struct_impl!(AddPartToResource (resource_id: u8, part_id: u32) -> super::Result, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(AddResourceEntry (resource_id: u8, resource: super::Resource) -> super::Result<(u8, super::Resource, ), super::Error, >, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Resource (resource_id: u8) -> super::Result, 2, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -162,11 +169,23 @@ pub mod rmrk_resource { #[codec(crate = sails_rs::scale_codec)] #[reflect_hash(crate = sails_rs)] pub enum RmrkResourceEvents { + #[codec(index = 0)] PartAdded { resource_id: u8, part_id: u32 }, + #[codec(index = 1)] ResourceAdded { resource_id: u8 }, } - impl sails_rs::client::Event for RmrkResourceEvents { - const EVENT_NAMES: &'static [Route] = &["PartAdded", "ResourceAdded"]; + impl RmrkResourceEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::PartAdded { .. } => 0, + Self::ResourceAdded { .. } => 1, + } + } + } + impl sails_rs::client::Event for RmrkResourceEvents {} + impl sails_rs::client::Identifiable for RmrkResourceEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for RmrkResourceImpl { type Event = RmrkResourceEvents; diff --git a/examples/rmrk/resource/wasm/tests/resources.rs b/examples/rmrk/resource/wasm/tests/resources.rs index 855684a9..4933632d 100644 --- a/examples/rmrk/resource/wasm/tests/resources.rs +++ b/examples/rmrk/resource/wasm/tests/resources.rs @@ -1,10 +1,10 @@ use rmrk_catalog::services::parts::{FixedPart, Part}; use rmrk_resource::client::{ self, RmrkResource, RmrkResourceProgram, - rmrk_resource::{RmrkResource as _, RmrkResourceImpl}, + rmrk_resource::{RmrkResource as _, RmrkResourceImpl, io}, }; +use rmrk_resource_app::catalogs; use rmrk_resource_app::services::{ - ResourceStorageEvent, errors::{Error as ResourceStorageError, Result as ResourceStorageResult}, resources::{ComposedResource, PartId, Resource, ResourceId}, }; @@ -14,6 +14,7 @@ use sails_rs::{ collections::BTreeMap, errors::Result, gtest::{BlockRunResult, Program, System}, + meta::SailsMessageHeader, }; const CATALOG_PROGRAM_WASM_PATH: &str = "../../../../target/wasm32-gear/debug/rmrk_catalog.wasm"; @@ -22,20 +23,6 @@ const RESOURCE_PROGRAM_WASM_PATH: &str = "../../../../target/wasm32-gear/debug/r const ADMIN_ID: u64 = 10; const NON_ADMIN_ID: u64 = 11; -mod resources { - pub const CTOR_FUNC_NAME: &str = "New"; - pub const RESOURCE_SERVICE_NAME: &str = "RmrkResource"; - pub const ADD_RESOURCE_ENTRY_FUNC_NAME: &str = "AddResourceEntry"; - pub const ADD_PART_TO_RESOURCE_FUNC_NAME: &str = "AddPartToResource"; - pub const RESOURCE_FUNC_NAME: &str = "Resource"; -} - -mod catalog { - pub const CTOR_FUNC_NAME: &str = "New"; - pub const ADD_PARTS_FUNC_NAME: &str = "AddParts"; - pub const CATALOG_SERVICE_NAME: &str = "RmrkCatalog"; -} - const RESOURCE_ID: ResourceId = 42; const PART_ID: PartId = 15; @@ -55,24 +42,27 @@ fn adding_resource_to_storage_by_admin_succeeds() { let run_result = fixture.add_resource(ADMIN_ID, RESOURCE_ID, &resource); // Assert + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddResourceEntry::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); let expected_response = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_RESOURCE_ENTRY_FUNC_NAME.encode(), + header.encode(), (Ok((RESOURCE_ID, &resource)) as ResourceStorageResult<(u8, &Resource)>).encode(), ] .concat(); assert!(run_result.contains(&(ADMIN_ID, expected_response))); - let expected_event = [ - resources::RESOURCE_SERVICE_NAME.encode().as_slice(), - "ResourceAdded".encode().as_slice(), - &ResourceStorageEvent::ResourceAdded { - resource_id: RESOURCE_ID, - } - .encode() - .as_slice()[1..], - ] - .concat(); + let event = client::rmrk_resource::events::RmrkResourceEvents::ResourceAdded { + resource_id: RESOURCE_ID, + }; + let event_header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + event.entry_id(), + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); + let expected_event = [event_header.encode(), RESOURCE_ID.encode()].concat(); assert!(run_result.contains(&(0, expected_event))); assert_eq!( @@ -106,9 +96,13 @@ async fn adding_resource_to_storage_by_admin_succeeds_async() { assert!(reply.is_ok()); let reply = reply.unwrap(); + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddResourceEntry::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); let expected_reply = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_RESOURCE_ENTRY_FUNC_NAME.encode(), + header.encode(), (Ok((RESOURCE_ID, &resource)) as ResourceStorageResult<(u8, &Resource)>).encode(), ] .concat(); @@ -169,9 +163,13 @@ fn adding_existing_part_to_resource_by_admin_succeeds() { let run_result = fixture.add_part_to_resource(ADMIN_ID, RESOURCE_ID, PART_ID); // Assert + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddPartToResource::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); let expected_response = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_PART_TO_RESOURCE_FUNC_NAME.encode(), + header.encode(), (Ok(PART_ID) as ResourceStorageResult).encode(), ] .concat(); @@ -192,6 +190,17 @@ fn adding_existing_part_to_resource_by_admin_succeeds() { async fn adding_existing_part_to_resource_by_admin_via_client_succeeds() { // Arrange let fixture = Fixture::new(); + + let mut parts = BTreeMap::new(); + parts.insert( + PART_ID, + Part::Fixed(FixedPart { + z: Some(1), + metadata_uri: "".into(), + }), + ); + fixture.add_parts(ADMIN_ID, &parts); + let resource = client::rmrk_resource::Resource::Composed(client::rmrk_resource::ComposedResource { src: "".into(), @@ -253,9 +262,13 @@ fn adding_non_existing_part_to_resource_fails() { let run_result = fixture.add_part_to_resource(ADMIN_ID, RESOURCE_ID, PART_ID); // Assert + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddPartToResource::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); let expected_response = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_PART_TO_RESOURCE_FUNC_NAME.encode(), + header.encode(), (Err(ResourceStorageError::PartNotFound) as ResourceStorageResult).encode(), ] .concat(); @@ -287,13 +300,15 @@ impl SystemFixture { fn create_catalog_program(system: &System) -> ActorId { let catalog_program = Program::from_file(system, CATALOG_PROGRAM_WASM_PATH); - catalog_program.send_bytes(ADMIN_ID, catalog::CTOR_FUNC_NAME.encode()); + let header = SailsMessageHeader::v1(InterfaceId::zero(), 0, 0); + catalog_program.send_bytes(ADMIN_ID, header.encode()); catalog_program.id() } fn create_resource_program(system: &System) -> ActorId { let resource_program = Program::from_file(system, RESOURCE_PROGRAM_WASM_PATH); - resource_program.send_bytes(ADMIN_ID, resources::CTOR_FUNC_NAME.encode()); + let header = SailsMessageHeader::v1(InterfaceId::zero(), 0, 0); + resource_program.send_bytes(ADMIN_ID, header.encode()); resource_program.id() } @@ -312,13 +327,12 @@ impl SystemFixture { resource: &Resource, ) -> BlockRunResult { let program = self.resource_program(); - let encoded_request = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_RESOURCE_ENTRY_FUNC_NAME.encode(), - resource_id.encode(), - resource.encode(), - ] - .concat(); + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddResourceEntry::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); + let encoded_request = [header.encode(), resource_id.encode(), resource.encode()].concat(); let _message_id = program.send_bytes(actor_id, encoded_request); self.system.run_next_block() } @@ -330,13 +344,12 @@ impl SystemFixture { part_id: PartId, ) -> BlockRunResult { let program = self.resource_program(); - let encoded_request = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_PART_TO_RESOURCE_FUNC_NAME.encode(), - resource_id.encode(), - part_id.encode(), - ] - .concat(); + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddPartToResource::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); + let encoded_request = [header.encode(), resource_id.encode(), part_id.encode()].concat(); let _message_id = program.send_bytes(actor_id, encoded_request); self.system.run_next_block() } @@ -347,14 +360,12 @@ impl SystemFixture { resource_id: ResourceId, ) -> Option> { let program = self.resource_program(); - let encoded_service_name = resources::RESOURCE_SERVICE_NAME.encode(); - let encoded_func_name = resources::RESOURCE_FUNC_NAME.encode(); - let encoded_request = [ - encoded_service_name.clone(), - encoded_func_name.clone(), - resource_id.encode(), - ] - .concat(); + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::Resource::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); + let encoded_request = [header.encode(), resource_id.encode()].concat(); let _message_id = program.send_bytes(actor_id, encoded_request); let run_result = self.system.run_next_block(); run_result @@ -363,23 +374,22 @@ impl SystemFixture { .find(|l| { l.destination() == actor_id.into() && l.source() == program.id() - && l.payload().starts_with(&encoded_service_name) - && l.payload()[encoded_service_name.len()..].starts_with(&encoded_func_name) + && l.payload().starts_with(&header.encode()) }) .map(|l| { - let mut p = &l.payload()[encoded_service_name.len() + encoded_func_name.len()..]; + let mut p = &l.payload()[(header.hlen().inner() as usize)..]; ResourceStorageResult::::decode(&mut p).unwrap() }) } fn add_parts(&self, actor_id: u64, parts: &BTreeMap) -> BlockRunResult { let program = self.catalog_program(); - let encoded_request = [ - catalog::CATALOG_SERVICE_NAME.encode(), - catalog::ADD_PARTS_FUNC_NAME.encode(), - parts.encode(), - ] - .concat(); + let header = SailsMessageHeader::v1( + catalogs::rmrk_catalog::RmrkCatalogImpl::INTERFACE_ID, + catalogs::rmrk_catalog::io::AddParts::ENTRY_ID, + catalogs::RmrkCatalogProgram::ROUTE_ID_RMRK_CATALOG, + ); + let encoded_request = [header.encode(), parts.encode()].concat(); let _message_id = program.send_bytes(actor_id, encoded_request); self.system.run_next_block() } @@ -412,30 +422,15 @@ impl Fixture { fn create_catalog_program(system: &System) -> ActorId { let catalog_program = Program::from_file(system, CATALOG_PROGRAM_WASM_PATH); - catalog_program.send_bytes(ADMIN_ID, catalog::CTOR_FUNC_NAME.encode()); - - let mut parts = BTreeMap::new(); - parts.insert( - PART_ID, - Part::Fixed(FixedPart { - z: Some(1), - metadata_uri: "".into(), - }), - ); - let encoded_request = [ - catalog::CATALOG_SERVICE_NAME.encode(), - catalog::ADD_PARTS_FUNC_NAME.encode(), - parts.encode(), - ] - .concat(); - let _message_id = catalog_program.send_bytes(ADMIN_ID, encoded_request); - system.run_next_block(); + let header = SailsMessageHeader::v1(InterfaceId::zero(), 0, 0); + catalog_program.send_bytes(ADMIN_ID, header.encode()); catalog_program.id() } fn create_resource_program(system: &System) -> ActorId { let resource_program = Program::from_file(system, RESOURCE_PROGRAM_WASM_PATH); - resource_program.send_bytes(ADMIN_ID, resources::CTOR_FUNC_NAME.encode()); + let header = SailsMessageHeader::v1(InterfaceId::zero(), 0, 0); + resource_program.send_bytes(ADMIN_ID, header.encode()); resource_program.id() } @@ -451,13 +446,12 @@ impl Fixture { resource_id: ResourceId, resource: &Resource, ) -> Result, GtestError> { - let encoded_request = [ - resources::RESOURCE_SERVICE_NAME.encode(), - resources::ADD_RESOURCE_ENTRY_FUNC_NAME.encode(), - resource_id.encode(), - resource.encode(), - ] - .concat(); + let header = SailsMessageHeader::v1( + RmrkResourceImpl::INTERFACE_ID, + io::AddResourceEntry::ENTRY_ID, + RmrkResourceProgram::ROUTE_ID_RMRK_RESOURCE, + ); + let encoded_request = [header.encode(), resource_id.encode(), resource.encode()].concat(); self.env .send_for_reply( self.resource_program_id, @@ -508,4 +502,20 @@ impl Fixture { .with_actor_id(actor_id.into()) .await } + + fn add_parts(&self, actor_id: u64, parts: &BTreeMap) -> BlockRunResult { + let program = self + .env + .system() + .get_program(self.catalog_program_id) + .unwrap(); + let header = SailsMessageHeader::v1( + catalogs::rmrk_catalog::RmrkCatalogImpl::INTERFACE_ID, + catalogs::rmrk_catalog::io::AddParts::ENTRY_ID, + catalogs::RmrkCatalogProgram::ROUTE_ID_RMRK_CATALOG, + ); + let encoded_request = [header.encode(), parts.encode()].concat(); + let _message_id = program.send_bytes(actor_id, encoded_request); + self.env.system().run_next_block() + } } diff --git a/rs/client-gen/src/ctor_generators.rs b/rs/client-gen/src/ctor_generators.rs index 9da4056c..d0a7e703 100644 --- a/rs/client-gen/src/ctor_generators.rs +++ b/rs/client-gen/src/ctor_generators.rs @@ -3,6 +3,7 @@ use convert_case::{Case, Casing}; use genco::prelude::*; use rust::Tokens; use sails_idl_parser_v2::{ast, visitor::Visitor}; +use std::collections::HashMap; pub(crate) struct CtorGenerator<'ast> { program_name: &'ast str, @@ -10,6 +11,7 @@ pub(crate) struct CtorGenerator<'ast> { ctor_tokens: Tokens, io_tokens: Tokens, trait_ctors_tokens: Tokens, + entry_ids: HashMap<&'ast str, u16>, } impl<'ast> CtorGenerator<'ast> { @@ -20,6 +22,7 @@ impl<'ast> CtorGenerator<'ast> { ctor_tokens: Tokens::new(), io_tokens: Tokens::new(), trait_ctors_tokens: Tokens::new(), + entry_ids: HashMap::new(), } } @@ -45,6 +48,14 @@ impl<'ast> CtorGenerator<'ast> { } impl<'ast> Visitor<'ast> for CtorGenerator<'ast> { + fn visit_program_unit(&mut self, program: &'ast ast::ProgramUnit) { + for (idx, ctor) in program.ctors.iter().enumerate() { + self.entry_ids.insert(&ctor.name, idx as u16); + } + + sails_idl_parser_v2::visitor::accept_program_unit(program, self); + } + fn visit_ctor_func(&mut self, func: &'ast ast::CtorFunc) { let fn_name = &func.name; let fn_name_snake = &fn_name.to_case(Case::Snake); @@ -74,8 +85,9 @@ impl<'ast> Visitor<'ast> for CtorGenerator<'ast> { }; let params_with_types_super = &fn_args_with_types_path(&func.params, "super"); + let entry_id = self.entry_ids.get(func.name.as_str()).copied().unwrap_or(0); quote_in! { self.io_tokens => - $(self.sails_path)::io_struct_impl!($fn_name ($params_with_types_super) -> ()); + $(self.sails_path)::io_struct_impl!($fn_name ($params_with_types_super) -> (), $entry_id); }; } } diff --git a/rs/client-gen/src/events_generator.rs b/rs/client-gen/src/events_generator.rs index fba560f3..510c190d 100644 --- a/rs/client-gen/src/events_generator.rs +++ b/rs/client-gen/src/events_generator.rs @@ -1,5 +1,6 @@ use genco::prelude::*; use sails_idl_parser_v2::{ast, visitor, visitor::Visitor}; +use std::collections::HashMap; use crate::helpers::generate_doc_comments; @@ -7,14 +8,20 @@ pub(crate) struct EventsModuleGenerator<'ast> { service_name: &'ast str, sails_path: &'ast str, tokens: rust::Tokens, + entry_ids: HashMap<&'ast str, u16>, } impl<'ast> EventsModuleGenerator<'ast> { - pub(crate) fn new(service_name: &'ast str, sails_path: &'ast str) -> Self { + pub(crate) fn new( + service_name: &'ast str, + sails_path: &'ast str, + entry_ids: HashMap<&'ast str, u16>, + ) -> Self { Self { service_name, sails_path, tokens: rust::Tokens::new(), + entry_ids, } } @@ -26,12 +33,6 @@ impl<'ast> EventsModuleGenerator<'ast> { impl<'ast> Visitor<'ast> for EventsModuleGenerator<'ast> { fn visit_service_unit(&mut self, service: &'ast ast::ServiceUnit) { let events_name = &format!("{}Events", self.service_name); - let event_names = service - .events - .iter() - .map(|e| format!("\"{}\"", e.name)) - .collect::>() - .join(", "); quote_in! { self.tokens => $['\n'] @@ -48,11 +49,22 @@ impl<'ast> Visitor<'ast> for EventsModuleGenerator<'ast> { quote_in! { self.tokens => $['\r'] $("}") - }; - quote_in! { self.tokens => - impl $(self.sails_path)::client::Event for $events_name { - const EVENT_NAMES: &'static [Route] = &[$event_names]; + $['\r'] + impl $events_name { + pub fn entry_id(&self) -> u16 { + match self { + $(for event in &service.events join ($['\r']) => + Self::$(&event.name) { .. } => $(self.entry_ids.get(event.name.as_str()).copied().unwrap_or(0)), + ) + } + } + } + + impl $(self.sails_path)::client::Event for $events_name {} + + impl $(self.sails_path)::client::Identifiable for $events_name { + const INTERFACE_ID: $(self.sails_path)::InterfaceId = <$(self.service_name)Impl as $(self.sails_path)::client::Identifiable>::INTERFACE_ID; } impl $(self.sails_path)::client::ServiceWithEvents for $(self.service_name)Impl { @@ -69,14 +81,19 @@ impl<'ast> Visitor<'ast> for EventsModuleGenerator<'ast> { generate_doc_comments(&mut self.tokens, &event.docs); let variant_name = &event.name; + let entry_id = self + .entry_ids + .get(event.name.as_str()) + .copied() + .unwrap_or(0); if event.def.is_unit() { - // Unit variant: `Variant,` quote_in! { self.tokens => - $['\r'] $variant_name, + $['\r'] + #[codec(index = $entry_id)] + $variant_name, }; } else if event.def.is_tuple() { - // Tuple variant: `Variant(Type1, Type2),` let mut field_tokens = rust::Tokens::new(); for field in &event.def.fields { let type_code = @@ -85,10 +102,11 @@ impl<'ast> Visitor<'ast> for EventsModuleGenerator<'ast> { field_tokens.append(", "); } quote_in! { self.tokens => - $['\r'] $variant_name($field_tokens), + $['\r'] + #[codec(index = $entry_id)] + $variant_name($field_tokens), }; } else { - // Struct variant: `Variant { field1: Type1, ... },` let mut field_tokens = rust::Tokens::new(); for field in &event.def.fields { generate_doc_comments(&mut field_tokens, &field.docs); @@ -100,7 +118,9 @@ impl<'ast> Visitor<'ast> for EventsModuleGenerator<'ast> { }; } quote_in! { self.tokens => - $['\r'] $variant_name { + $['\r'] + #[codec(index = $entry_id)] + $variant_name { $(field_tokens) $['\r'] }, }; diff --git a/rs/client-gen/src/root_generator.rs b/rs/client-gen/src/root_generator.rs index 8a8dedec..9bbf92de 100644 --- a/rs/client-gen/src/root_generator.rs +++ b/rs/client-gen/src/root_generator.rs @@ -12,12 +12,12 @@ pub(crate) struct RootGenerator<'ast> { tokens: Tokens, service_impl_tokens: Tokens, service_trait_tokens: Tokens, + program_meta_tokens: Tokens, program_name: Option<&'ast str>, mocks_feature_name: Option<&'ast str>, sails_path: &'ast str, external_types: HashMap<&'ast str, &'ast str>, no_derive_traits: bool, - program_exported_services: Vec<&'ast str>, program_types: HashSet<&'ast str>, } @@ -32,12 +32,12 @@ impl<'ast> RootGenerator<'ast> { tokens: Tokens::new(), service_impl_tokens: Tokens::new(), service_trait_tokens: Tokens::new(), + program_meta_tokens: Tokens::new(), program_name: None, mocks_feature_name, sails_path, external_types, no_derive_traits, - program_exported_services: Vec::new(), program_types: HashSet::new(), } } @@ -70,6 +70,10 @@ impl<'ast> RootGenerator<'ast> { quote_in! { tokens => pub struct $(program_name)Program; + impl $(program_name)Program { + $(self.program_meta_tokens) + } + impl $(self.sails_path)::client::Program for $(program_name)Program {} pub trait $program_name { @@ -109,14 +113,6 @@ impl<'ast> Visitor<'ast> for RootGenerator<'ast> { ctor_gen.visit_program_unit(program); self.tokens.extend(ctor_gen.finalize()); - for service_item in &program.services { - let service_name = service_item - .route - .as_ref() - .unwrap_or(&service_item.name.name); - self.program_exported_services.push(service_name); - } - sails_idl_parser_v2::visitor::accept_program_unit(program, self); } @@ -126,6 +122,10 @@ impl<'ast> Visitor<'ast> for RootGenerator<'ast> { self.sails_path, &self.external_types, self.mocks_feature_name, + service + .name + .interface_id + .expect("Service must have an interface ID"), self.no_derive_traits, ); client_gen.visit_service_unit(service); @@ -151,16 +151,24 @@ impl<'ast> Visitor<'ast> for RootGenerator<'ast> { let method_name = service_route.to_case(Case::Snake); let name_pascal_case = service_item.name.name.to_case(Case::Pascal); let name_snake_case = service_item.name.name.to_case(Case::Snake); + let program_name = self.program_name.unwrap(); + let program_program_name = format!("{program_name}Program"); generate_doc_comments(&mut self.service_trait_tokens, &service_item.docs); + let route_id_const_name = format!("ROUTE_ID_{}", service_route.to_case(Case::UpperSnake)); + + quote_in!(self.program_meta_tokens => + pub const $(&route_id_const_name): u8 = $(service_item.route_idx); + ); + quote_in!(self.service_trait_tokens => $['\r'] fn $(&method_name)(&self) -> $(self.sails_path)::client::Service<$(&name_snake_case)::$(&name_pascal_case)Impl, Self::Env>; ); quote_in!(self.service_impl_tokens => $['\r'] fn $(&method_name)(&self) -> $(self.sails_path)::client::Service<$(&name_snake_case)::$(&name_pascal_case)Impl, Self::Env> { - self.service(stringify!($(&name_pascal_case))) + self.service($(&program_program_name)::$(&route_id_const_name)) } ); } diff --git a/rs/client-gen/src/service_generators.rs b/rs/client-gen/src/service_generators.rs index 2f5131de..eb4378ed 100644 --- a/rs/client-gen/src/service_generators.rs +++ b/rs/client-gen/src/service_generators.rs @@ -5,7 +5,6 @@ use crate::type_generators::{TopLevelTypeGenerator, generate_type_decl_with_path use convert_case::{Case, Casing}; use genco::prelude::*; use rust::Tokens; -use sails_idl_meta::ServiceIdent; use sails_idl_parser_v2::{ast, visitor, visitor::Visitor}; use std::collections::HashMap; @@ -21,6 +20,8 @@ pub(crate) struct ServiceGenerator<'ast> { events_tokens: Tokens, types_tokens: Tokens, mocks_tokens: Tokens, + interface_id: sails_idl_meta::InterfaceId, + entry_ids: HashMap<&'ast str, u16>, no_derive_traits: bool, } @@ -30,6 +31,7 @@ impl<'ast> ServiceGenerator<'ast> { sails_path: &'ast str, external_types: &'ast HashMap<&'ast str, &'ast str>, mocks_feature_name: Option<&'ast str>, + interface_id: sails_idl_meta::InterfaceId, no_derive_traits: bool, ) -> Self { Self { @@ -43,6 +45,8 @@ impl<'ast> ServiceGenerator<'ast> { events_tokens: Tokens::new(), types_tokens: Tokens::new(), mocks_tokens: Tokens::new(), + interface_id, + entry_ids: HashMap::new(), no_derive_traits, } } @@ -63,6 +67,12 @@ impl<'ast> ServiceGenerator<'ast> { } else { quote!() }; + + let bytes = self.interface_id.as_bytes().iter().copied(); + let interface_id_tokens = quote! { + const INTERFACE_ID: $(self.sails_path)::InterfaceId = $(self.sails_path)::InterfaceId::from_bytes_8([ $(for b in bytes join (, ) => $b) ]); + }; + quote! { $['\n'] pub mod $service_name_snake { @@ -77,6 +87,10 @@ impl<'ast> ServiceGenerator<'ast> { pub struct $(self.service_name)Impl; + impl $(self.sails_path)::client::Identifiable for $(self.service_name)Impl { + $interface_id_tokens + } + impl $(self.service_name) for $(self.sails_path)::client::Service<$(self.service_name)Impl, E> { type Env = E; $(self.impl_tokens) @@ -99,13 +113,26 @@ impl<'ast> ServiceGenerator<'ast> { // using quote_in instead of tokens.append impl<'ast> Visitor<'ast> for ServiceGenerator<'ast> { fn visit_service_unit(&mut self, service: &'ast ast::ServiceUnit) { + let (mut commands, mut queries): (Vec<_>, Vec<_>) = service + .funcs + .iter() + .partition(|f| f.kind != ast::FunctionKind::Query); + + commands.sort_by_key(|f| f.name.to_lowercase()); + queries.sort_by_key(|f| f.name.to_lowercase()); + + for (entry_id, func) in commands.into_iter().chain(queries.into_iter()).enumerate() { + self.entry_ids.insert(func.name.as_str(), entry_id as u16); + } + + for (idx, event) in service.events.iter().enumerate() { + self.entry_ids.insert(event.name.as_str(), idx as u16); + } + visitor::accept_service_unit(service, self); - for ServiceIdent { - name, - interface_id: _, - } in &service.extends - { + for service_ident in &service.extends { + let name = &service_ident.name; let method_name = name.to_case(Case::Snake); let impl_name = name.to_case(Case::Pascal); let mod_name = name.to_case(Case::Snake); @@ -126,7 +153,11 @@ impl<'ast> Visitor<'ast> for ServiceGenerator<'ast> { self.mocks_tokens.extend(mock_gen.finalize()); if !service.events.is_empty() { - let mut events_mod_gen = EventsModuleGenerator::new(self.service_name, self.sails_path); + let mut events_mod_gen = EventsModuleGenerator::new( + self.service_name, + self.sails_path, + self.entry_ids.clone(), + ); events_mod_gen.visit_service_unit(service); self.events_tokens = events_mod_gen.finalize(); } @@ -176,8 +207,10 @@ impl<'ast> Visitor<'ast> for ServiceGenerator<'ast> { }; let params_with_types_super = &fn_args_with_types_path(&func.params, "super"); + let entry_id = self.entry_ids.get(func.name.as_str()).copied().unwrap_or(0); + quote_in! { self.io_tokens => - $(self.sails_path)::io_struct_impl!($fn_name ($params_with_types_super) -> $output_type_decl_code); + $(self.sails_path)::io_struct_impl!($fn_name ($params_with_types_super) -> $output_type_decl_code, $entry_id, ::INTERFACE_ID); }; } } diff --git a/rs/client-gen/tests/snapshots/generator__basic_works.snap b/rs/client-gen/tests/snapshots/generator__basic_works.snap index a2dd46c1..1847d4c9 100644 --- a/rs/client-gen/tests/snapshots/generator__basic_works.snap +++ b/rs/client-gen/tests/snapshots/generator__basic_works.snap @@ -44,6 +44,10 @@ pub mod basic { ) -> sails_rs::client::PendingCall; } pub struct BasicImpl; + impl sails_rs::client::Identifiable for BasicImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([82, 241, 49, 169, 231, 31, 0, 230]); + } impl Basic for sails_rs::client::Service { type Env = E; fn do_that( @@ -63,8 +67,8 @@ pub mod basic { pub mod io { use super::*; - sails_rs::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8); - sails_rs::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16); + sails_rs::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16, 1, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/rs/client-gen/tests/snapshots/generator__complex_type_generation_works.snap b/rs/client-gen/tests/snapshots/generator__complex_type_generation_works.snap index a0c1fd13..c12bf5ac 100644 --- a/rs/client-gen/tests/snapshots/generator__complex_type_generation_works.snap +++ b/rs/client-gen/tests/snapshots/generator__complex_type_generation_works.snap @@ -9,6 +9,10 @@ extern crate std; #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct ComplexTypesProgramProgram; +impl ComplexTypesProgramProgram { + pub const ROUTE_ID_MY_COMPLEX_SERVICE: u8 = 1; + pub const ROUTE_ID_ANOTHER_SERVICE: u8 = 2; +} impl sails_rs::client::Program for ComplexTypesProgramProgram {} pub trait ComplexTypesProgram { type Env: sails_rs::client::GearEnv; @@ -26,12 +30,12 @@ impl ComplexTypesProgram fn my_complex_service( &self, ) -> sails_rs::client::Service { - self.service(stringify!(MyComplexService)) + self.service(ComplexTypesProgramProgram::ROUTE_ID_MY_COMPLEX_SERVICE) } fn another_service( &self, ) -> sails_rs::client::Service { - self.service(stringify!(AnotherService)) + self.service(ComplexTypesProgramProgram::ROUTE_ID_ANOTHER_SERVICE) } } pub trait ComplexTypesProgramCtors { @@ -57,7 +61,7 @@ impl ComplexTypesProgramCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(NewProgram (initial_count: u32, id_prefix: String) -> ()); + sails_rs::io_struct_impl!(NewProgram (initial_count: u32, id_prefix: String) -> (), 0); } pub mod my_complex_service { @@ -174,6 +178,10 @@ pub mod my_complex_service { fn get_info(&self) -> sails_rs::client::PendingCall; } pub struct MyComplexServiceImpl; + impl sails_rs::client::Identifiable for MyComplexServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([125, 102, 14, 174, 143, 201, 77, 154]); + } impl MyComplexService for sails_rs::client::Service { @@ -220,12 +228,12 @@ pub mod my_complex_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(GetData (key: String) -> super::Result); - sails_rs::io_struct_impl!(Initialize (start_data: super::ProgramGlobalInfo, max_size: super::NonZeroU32) -> super::Result<(), super::ErrorType, >); - sails_rs::io_struct_impl!(ProcessGenericData (input_data: super::GenericData, list_of_generics: Vec>, optional_generic_result: super::Option, >) -> super::GenericData); - sails_rs::io_struct_impl!(UpdateStatus (id: u64, new_status: super::ServiceStatus, metadata: super::Option) -> super::GenericResult); - sails_rs::io_struct_impl!(GetActorIds (count: u32) -> Vec); - sails_rs::io_struct_impl!(GetInfo () -> super::ProgramGlobalInfo); + sails_rs::io_struct_impl!(GetData (key: String) -> super::Result, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Initialize (start_data: super::ProgramGlobalInfo, max_size: super::NonZeroU32) -> super::Result<(), super::ErrorType, >, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(ProcessGenericData (input_data: super::GenericData, list_of_generics: Vec>, optional_generic_result: super::Option, >) -> super::GenericData, 2, ::INTERFACE_ID); + sails_rs::io_struct_impl!(UpdateStatus (id: u64, new_status: super::ServiceStatus, metadata: super::Option) -> super::GenericResult, 3, ::INTERFACE_ID); + sails_rs::io_struct_impl!(GetActorIds (count: u32) -> Vec, 4, ::INTERFACE_ID); + sails_rs::io_struct_impl!(GetInfo () -> super::ProgramGlobalInfo, 5, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -257,6 +265,10 @@ pub mod another_service { ) -> sails_rs::client::PendingCall; } pub struct AnotherServiceImpl; + impl sails_rs::client::Identifiable for AnotherServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([155, 46, 27, 116, 89, 52, 232, 187]); + } impl AnotherService for sails_rs::client::Service { @@ -274,8 +286,8 @@ pub mod another_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(Ping () -> String); - sails_rs::io_struct_impl!(ProcessValues (data: Vec) -> super::Result<(), super::ErrorType, >); + sails_rs::io_struct_impl!(Ping () -> String, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(ProcessValues (data: Vec) -> super::Result<(), super::ErrorType, >, 1, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/rs/client-gen/tests/snapshots/generator__events_works.snap b/rs/client-gen/tests/snapshots/generator__events_works.snap index 034f80a4..36f6f039 100644 --- a/rs/client-gen/tests/snapshots/generator__events_works.snap +++ b/rs/client-gen/tests/snapshots/generator__events_works.snap @@ -29,6 +29,10 @@ pub mod service_with_events { ) -> sails_rs::client::PendingCall; } pub struct ServiceWithEventsImpl; + impl sails_rs::client::Identifiable for ServiceWithEventsImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([186, 231, 26, 185, 242, 135, 49, 106]); + } impl ServiceWithEvents for sails_rs::client::Service { @@ -44,7 +48,7 @@ pub mod service_with_events { pub mod io { use super::*; - sails_rs::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64); + sails_rs::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64, 0, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -54,13 +58,29 @@ pub mod service_with_events { #[codec(crate = sails_rs::scale_codec)] #[reflect_hash(crate = sails_rs)] pub enum ServiceWithEventsEvents { + #[codec(index = 0)] One(u64), + #[codec(index = 1)] Reset, + #[codec(index = 2)] Three(MyParam), + #[codec(index = 3)] Two { id: u8, reference: u64 }, } - impl sails_rs::client::Event for ServiceWithEventsEvents { - const EVENT_NAMES: &'static [Route] = &["One", "Reset", "Three", "Two"]; + impl ServiceWithEventsEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::One { .. } => 0, + Self::Reset { .. } => 1, + Self::Three { .. } => 2, + Self::Two { .. } => 3, + } + } + } + impl sails_rs::client::Event for ServiceWithEventsEvents {} + impl sails_rs::client::Identifiable for ServiceWithEventsEvents { + const INTERFACE_ID: sails_rs::InterfaceId = + ::INTERFACE_ID; } impl sails_rs::client::ServiceWithEvents for ServiceWithEventsImpl { type Event = ServiceWithEventsEvents; diff --git a/rs/client-gen/tests/snapshots/generator__external_types.snap b/rs/client-gen/tests/snapshots/generator__external_types.snap index ca292028..1a5cfdb5 100644 --- a/rs/client-gen/tests/snapshots/generator__external_types.snap +++ b/rs/client-gen/tests/snapshots/generator__external_types.snap @@ -34,6 +34,10 @@ pub mod service { ) -> my_crate::sails::client::PendingCall; } pub struct ServiceImpl; + impl my_crate::sails::client::Identifiable for ServiceImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([82, 241, 49, 169, 231, 31, 0, 230]); + } impl Service for my_crate::sails::client::Service { @@ -55,7 +59,7 @@ pub mod service { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8); - my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16); + my_crate::sails::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16, 1, ::INTERFACE_ID); } } diff --git a/rs/client-gen/tests/snapshots/generator__full_with_sails_path.snap b/rs/client-gen/tests/snapshots/generator__full_with_sails_path.snap index 3276deb7..e24077ee 100644 --- a/rs/client-gen/tests/snapshots/generator__full_with_sails_path.snap +++ b/rs/client-gen/tests/snapshots/generator__full_with_sails_path.snap @@ -6,6 +6,20 @@ expression: code #[allow(unused_imports)] use my_crate::sails::{client::*, collections::*, prelude::*}; pub struct FullCoverageProgramProgram; +impl FullCoverageProgramProgram { + pub const ROUTE_ID_CANVAS: u8 = 1; + pub const ROUTE_ID_PING_PONG: u8 = 2; + pub const ROUTE_ID_COUNTER: u8 = 3; + pub const ROUTE_ID_REFERENCES: u8 = 4; + pub const ROUTE_ID_THIS_THAT: u8 = 5; + pub const ROUTE_ID_VALUE_FEE: u8 = 6; + pub const ROUTE_ID_RMRK_CATALOG: u8 = 7; + pub const ROUTE_ID_NON_ZERO_PARAMS: u8 = 8; + pub const ROUTE_ID_SERVICE_WITH_EVENTS: u8 = 9; + pub const ROUTE_ID_BASIC: u8 = 10; + pub const ROUTE_ID_ANOTHER_SERVICE: u8 = 11; + pub const ROUTE_ID_MY_COMPLEX_SERVICE: u8 = 12; +} impl my_crate::sails::client::Program for FullCoverageProgramProgram {} pub trait FullCoverageProgram { type Env: my_crate::sails::client::GearEnv; @@ -50,53 +64,53 @@ impl FullCoverageProgram { type Env = E; fn canvas(&self) -> my_crate::sails::client::Service { - self.service(stringify!(Canvas)) + self.service(FullCoverageProgramProgram::ROUTE_ID_CANVAS) } fn ping_pong(&self) -> my_crate::sails::client::Service { - self.service(stringify!(PingPong)) + self.service(FullCoverageProgramProgram::ROUTE_ID_PING_PONG) } fn counter(&self) -> my_crate::sails::client::Service { - self.service(stringify!(Counter)) + self.service(FullCoverageProgramProgram::ROUTE_ID_COUNTER) } fn references( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(References)) + self.service(FullCoverageProgramProgram::ROUTE_ID_REFERENCES) } fn this_that(&self) -> my_crate::sails::client::Service { - self.service(stringify!(ThisThat)) + self.service(FullCoverageProgramProgram::ROUTE_ID_THIS_THAT) } fn value_fee(&self) -> my_crate::sails::client::Service { - self.service(stringify!(ValueFee)) + self.service(FullCoverageProgramProgram::ROUTE_ID_VALUE_FEE) } fn rmrk_catalog( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(RmrkCatalog)) + self.service(FullCoverageProgramProgram::ROUTE_ID_RMRK_CATALOG) } fn non_zero_params( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(NonZeroParams)) + self.service(FullCoverageProgramProgram::ROUTE_ID_NON_ZERO_PARAMS) } fn service_with_events( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(ServiceWithEvents)) + self.service(FullCoverageProgramProgram::ROUTE_ID_SERVICE_WITH_EVENTS) } fn basic(&self) -> my_crate::sails::client::Service { - self.service(stringify!(Basic)) + self.service(FullCoverageProgramProgram::ROUTE_ID_BASIC) } fn another_service( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(AnotherService)) + self.service(FullCoverageProgramProgram::ROUTE_ID_ANOTHER_SERVICE) } fn my_complex_service( &self, ) -> my_crate::sails::client::Service { - self.service(stringify!(MyComplexService)) + self.service(FullCoverageProgramProgram::ROUTE_ID_MY_COMPLEX_SERVICE) } } pub trait FullCoverageProgramCtors { @@ -134,8 +148,8 @@ impl FullCoverageProgramCtors pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Default () -> ()); - my_crate::sails::io_struct_impl!(WithOwner (owner: ActorId, initial_config: super::ProgramConfig) -> ()); + my_crate::sails::io_struct_impl!(Default () -> (), 0); + my_crate::sails::io_struct_impl!(WithOwner (owner: ActorId, initial_config: super::ProgramConfig) -> (), 1); } #[derive(PartialEq, Clone, Debug, Encode, Decode, TypeInfo, ReflectHash)] #[codec(crate = my_crate::sails::scale_codec)] @@ -233,6 +247,10 @@ pub mod canvas { ) -> my_crate::sails::client::Service; } pub struct CanvasImpl; + impl my_crate::sails::client::Identifiable for CanvasImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([159, 96, 48, 64, 97, 141, 24, 70]); + } impl Canvas for my_crate::sails::client::Service { @@ -282,10 +300,10 @@ pub mod canvas { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(ColorPoint (point: super::Point, color: super::Color) -> super::Result<(), super::ColorError>); - my_crate::sails::io_struct_impl!(KillPoint (point: super::Point) -> super::Result); - my_crate::sails::io_struct_impl!(Points (offset: u32, len: u32) -> super::Result, super::PointStatus, )>, String>); - my_crate::sails::io_struct_impl!(PointStatus (point: super::Point) -> super::Option); + my_crate::sails::io_struct_impl!(ColorPoint (point: super::Point, color: super::Color) -> super::Result<(), super::ColorError>, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(KillPoint (point: super::Point) -> super::Result, 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Points (offset: u32, len: u32) -> super::Result, super::PointStatus, )>, String>, 2, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(PointStatus (point: super::Point) -> super::Option, 3, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -295,16 +313,30 @@ pub mod canvas { #[codec(crate = my_crate::sails::scale_codec)] #[reflect_hash(crate = my_crate::sails)] pub enum CanvasEvents { + #[codec(index = 0)] E1, + #[codec(index = 1)] Jubilee { /// Amount of alive points. amount: u64, bits: Vec, }, + #[codec(index = 2)] StatusChanged(Point), } - impl my_crate::sails::client::Event for CanvasEvents { - const EVENT_NAMES: &'static [Route] = &["E1", "Jubilee", "StatusChanged"]; + impl CanvasEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::E1 { .. } => 0, + Self::Jubilee { .. } => 1, + Self::StatusChanged { .. } => 2, + } + } + } + impl my_crate::sails::client::Event for CanvasEvents {} + impl my_crate::sails::client::Identifiable for CanvasEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for CanvasImpl { type Event = CanvasEvents; @@ -322,6 +354,10 @@ pub mod ping_pong { ) -> my_crate::sails::client::PendingCall; } pub struct PingPongImpl; + impl my_crate::sails::client::Identifiable for PingPongImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([33, 189, 154, 154, 165, 29, 162, 100]); + } impl PingPong for my_crate::sails::client::Service { @@ -336,7 +372,7 @@ pub mod ping_pong { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Ping (input: String) -> super::Result); + my_crate::sails::io_struct_impl!(Ping (input: String) -> super::Result, 0, ::INTERFACE_ID); } } @@ -352,6 +388,10 @@ pub mod counter { fn value(&self) -> my_crate::sails::client::PendingCall; } pub struct CounterImpl; + impl my_crate::sails::client::Identifiable for CounterImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([87, 157, 109, 171, 164, 27, 125, 130]); + } impl Counter for my_crate::sails::client::Service { @@ -369,9 +409,9 @@ pub mod counter { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Add (value: u32) -> u32); - my_crate::sails::io_struct_impl!(Sub (value: u32) -> u32); - my_crate::sails::io_struct_impl!(Value () -> u32); + my_crate::sails::io_struct_impl!(Add (value: u32) -> u32, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Sub (value: u32) -> u32, 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Value () -> u32, 2, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -382,12 +422,24 @@ pub mod counter { #[reflect_hash(crate = my_crate::sails)] pub enum CounterEvents { /// Emitted when a new value is added to the counter + #[codec(index = 0)] Added(u32), /// Emitted when a value is subtracted from the counter + #[codec(index = 1)] Subtracted(u32), } - impl my_crate::sails::client::Event for CounterEvents { - const EVENT_NAMES: &'static [Route] = &["Added", "Subtracted"]; + impl CounterEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Added { .. } => 0, + Self::Subtracted { .. } => 1, + } + } + } + impl my_crate::sails::client::Event for CounterEvents {} + impl my_crate::sails::client::Identifiable for CounterEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for CounterImpl { type Event = CounterEvents; @@ -409,6 +461,10 @@ pub mod dog { fn position(&self) -> my_crate::sails::client::PendingCall; } pub struct DogImpl; + impl my_crate::sails::client::Identifiable for DogImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([75, 2, 200, 107, 128, 2, 138, 218]); + } impl Dog for my_crate::sails::client::Service { type Env = E; fn make_sound(&mut self) -> my_crate::sails::client::PendingCall { @@ -431,10 +487,10 @@ pub mod dog { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(MakeSound () -> String); - my_crate::sails::io_struct_impl!(Walk (dx: i32, dy: i32) -> ()); - my_crate::sails::io_struct_impl!(AvgWeight () -> u32); - my_crate::sails::io_struct_impl!(Position () -> (i32, i32, )); + my_crate::sails::io_struct_impl!(MakeSound () -> String, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Walk (dx: i32, dy: i32) -> (), 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(AvgWeight () -> u32, 2, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Position () -> (i32, i32, ), 3, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -444,11 +500,23 @@ pub mod dog { #[codec(crate = my_crate::sails::scale_codec)] #[reflect_hash(crate = my_crate::sails)] pub enum DogEvents { + #[codec(index = 0)] Barked, + #[codec(index = 1)] Walked { from: (i32, i32), to: (i32, i32) }, } - impl my_crate::sails::client::Event for DogEvents { - const EVENT_NAMES: &'static [Route] = &["Barked", "Walked"]; + impl DogEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Barked { .. } => 0, + Self::Walked { .. } => 1, + } + } + } + impl my_crate::sails::client::Event for DogEvents {} + impl my_crate::sails::client::Identifiable for DogEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for DogImpl { type Event = DogEvents; @@ -484,6 +552,10 @@ pub mod references { fn message(&self) -> my_crate::sails::client::PendingCall; } pub struct ReferencesImpl; + impl my_crate::sails::client::Identifiable for ReferencesImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([61, 171, 145, 177, 150, 71, 129, 98]); + } impl References for my_crate::sails::client::Service { @@ -525,14 +597,14 @@ pub mod references { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Add (v: u32) -> u32); - my_crate::sails::io_struct_impl!(AddByte (byte: u8) -> Vec); - my_crate::sails::io_struct_impl!(GuessNum (number: u8) -> super::Result); - my_crate::sails::io_struct_impl!(Incr () -> super::ReferenceCount); - my_crate::sails::io_struct_impl!(SetNum (number: u8) -> super::Result<(), String>); - my_crate::sails::io_struct_impl!(Baked () -> String); - my_crate::sails::io_struct_impl!(LastByte () -> super::Option); - my_crate::sails::io_struct_impl!(Message () -> super::Option); + my_crate::sails::io_struct_impl!(Add (v: u32) -> u32, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(AddByte (byte: u8) -> Vec, 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(GuessNum (number: u8) -> super::Result, 2, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Incr () -> super::ReferenceCount, 3, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(SetNum (number: u8) -> super::Result<(), String>, 4, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Baked () -> String, 5, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(LastByte () -> super::Option, 6, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Message () -> super::Option, 7, ::INTERFACE_ID); } } @@ -594,6 +666,10 @@ pub mod this_that { fn this(&self) -> my_crate::sails::client::PendingCall; } pub struct ThisThatImpl; + impl my_crate::sails::client::Identifiable for ThisThatImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([220, 131, 135, 131, 19, 27, 44, 105]); + } impl ThisThat for my_crate::sails::client::Service { @@ -626,11 +702,11 @@ pub mod this_that { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoThat (param: super::DoThatParam) -> super::Result<(ActorId, u32, super::ManyVariantsReply, ), (String, )>); - my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: String, p3: (super::Option, u8, ), p4: super::TupleStruct) -> (String, u32, )); - my_crate::sails::io_struct_impl!(Noop () -> ()); - my_crate::sails::io_struct_impl!(That () -> super::Result); - my_crate::sails::io_struct_impl!(This () -> u32); + my_crate::sails::io_struct_impl!(DoThat (param: super::DoThatParam) -> super::Result<(ActorId, u32, super::ManyVariantsReply, ), (String, )>, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: String, p3: (super::Option, u8, ), p4: super::TupleStruct) -> (String, u32, ), 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Noop () -> (), 2, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(That () -> super::Result, 3, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(This () -> u32, 4, ::INTERFACE_ID); } } @@ -645,6 +721,10 @@ pub mod value_fee { ) -> my_crate::sails::client::PendingCall; } pub struct ValueFeeImpl; + impl my_crate::sails::client::Identifiable for ValueFeeImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([65, 193, 8, 11, 78, 30, 141, 197]); + } impl ValueFee for my_crate::sails::client::Service { @@ -658,7 +738,7 @@ pub mod value_fee { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoSomethingAndTakeFee () -> bool); + my_crate::sails::io_struct_impl!(DoSomethingAndTakeFee () -> bool, 0, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -668,10 +748,20 @@ pub mod value_fee { #[codec(crate = my_crate::sails::scale_codec)] #[reflect_hash(crate = my_crate::sails)] pub enum ValueFeeEvents { + #[codec(index = 0)] Withheld(u128), } - impl my_crate::sails::client::Event for ValueFeeEvents { - const EVENT_NAMES: &'static [Route] = &["Withheld"]; + impl ValueFeeEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Withheld { .. } => 0, + } + } + } + impl my_crate::sails::client::Event for ValueFeeEvents {} + impl my_crate::sails::client::Identifiable for ValueFeeEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for ValueFeeImpl { type Event = ValueFeeEvents; @@ -692,6 +782,10 @@ pub mod pausable { fn unpause(&mut self) -> my_crate::sails::client::PendingCall; } pub struct PausableImpl; + impl my_crate::sails::client::Identifiable for PausableImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([119, 153, 244, 54, 223, 215, 83, 198]); + } impl Pausable for my_crate::sails::client::Service { @@ -706,8 +800,8 @@ pub mod pausable { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Pause () -> ()); - my_crate::sails::io_struct_impl!(Unpause () -> ()); + my_crate::sails::io_struct_impl!(Pause () -> (), 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Unpause () -> (), 1, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -717,11 +811,23 @@ pub mod pausable { #[codec(crate = my_crate::sails::scale_codec)] #[reflect_hash(crate = my_crate::sails)] pub enum PausableEvents { + #[codec(index = 0)] Paused, + #[codec(index = 1)] Unpaused, } - impl my_crate::sails::client::Event for PausableEvents { - const EVENT_NAMES: &'static [Route] = &["Paused", "Unpaused"]; + impl PausableEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Paused { .. } => 0, + Self::Unpaused { .. } => 1, + } + } + } + impl my_crate::sails::client::Event for PausableEvents {} + impl my_crate::sails::client::Identifiable for PausableEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for PausableImpl { type Event = PausableEvents; @@ -736,6 +842,10 @@ pub mod ownable { fn get_owner(&mut self) -> my_crate::sails::client::PendingCall; } pub struct OwnableImpl; + impl my_crate::sails::client::Identifiable for OwnableImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([45, 223, 161, 186, 121, 8, 187, 243]); + } impl Ownable for my_crate::sails::client::Service { @@ -747,7 +857,7 @@ pub mod ownable { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(GetOwner () -> ActorId); + my_crate::sails::io_struct_impl!(GetOwner () -> ActorId, 0, ::INTERFACE_ID); } } @@ -759,6 +869,10 @@ pub mod tippable { -> my_crate::sails::client::PendingCall; } pub struct TippableImpl; + impl my_crate::sails::client::Identifiable for TippableImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([237, 182, 209, 207, 204, 160, 182, 70]); + } impl Tippable for my_crate::sails::client::Service { @@ -773,7 +887,7 @@ pub mod tippable { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Tip (amount: u128) -> ()); + my_crate::sails::io_struct_impl!(Tip (amount: u128) -> (), 0, ::INTERFACE_ID); } } @@ -797,6 +911,10 @@ pub mod non_zero_params { ) -> my_crate::sails::client::PendingCall; } pub struct NonZeroParamsImpl; + impl my_crate::sails::client::Identifiable for NonZeroParamsImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([247, 238, 3, 214, 44, 137, 30, 3]); + } impl NonZeroParams for my_crate::sails::client::Service { @@ -812,7 +930,7 @@ pub mod non_zero_params { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64); + my_crate::sails::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64, 0, ::INTERFACE_ID); } } @@ -836,6 +954,10 @@ pub mod service_with_events { ) -> my_crate::sails::client::PendingCall; } pub struct ServiceWithEventsImpl; + impl my_crate::sails::client::Identifiable for ServiceWithEventsImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([192, 205, 152, 45, 145, 112, 193, 0]); + } impl ServiceWithEvents for my_crate::sails::client::Service { @@ -851,7 +973,7 @@ pub mod service_with_events { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64); + my_crate::sails::io_struct_impl!(DoThis (p1: U256, p2: super::MyParam) -> u64, 0, ::INTERFACE_ID); } #[cfg(not(target_arch = "wasm32"))] @@ -861,11 +983,23 @@ pub mod service_with_events { #[codec(crate = my_crate::sails::scale_codec)] #[reflect_hash(crate = my_crate::sails)] pub enum ServiceWithEventsEvents { + #[codec(index = 0)] Event1(u32), + #[codec(index = 1)] Event2 { field1: String, field2: u64 }, } - impl my_crate::sails::client::Event for ServiceWithEventsEvents { - const EVENT_NAMES: &'static [Route] = &["Event1", "Event2"]; + impl ServiceWithEventsEvents { + pub fn entry_id(&self) -> u16 { + match self { + Self::Event1 { .. } => 0, + Self::Event2 { .. } => 1, + } + } + } + impl my_crate::sails::client::Event for ServiceWithEventsEvents {} + impl my_crate::sails::client::Identifiable for ServiceWithEventsEvents { + const INTERFACE_ID: my_crate::sails::InterfaceId = + ::INTERFACE_ID; } impl my_crate::sails::client::ServiceWithEvents for ServiceWithEventsImpl { type Event = ServiceWithEventsEvents; @@ -908,6 +1042,10 @@ pub mod basic { ) -> my_crate::sails::client::PendingCall; } pub struct BasicImpl; + impl my_crate::sails::client::Identifiable for BasicImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([82, 241, 49, 169, 231, 31, 0, 230]); + } impl Basic for my_crate::sails::client::Service { type Env = E; fn do_that( @@ -927,8 +1065,8 @@ pub mod basic { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8); - my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16); + my_crate::sails::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16, 1, ::INTERFACE_ID); } } @@ -951,6 +1089,10 @@ pub mod another_service { ) -> my_crate::sails::client::PendingCall; } pub struct AnotherServiceImpl; + impl my_crate::sails::client::Identifiable for AnotherServiceImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([98, 254, 176, 83, 233, 74, 173, 234]); + } impl AnotherService for my_crate::sails::client::Service { @@ -968,8 +1110,8 @@ pub mod another_service { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(Ping () -> String); - my_crate::sails::io_struct_impl!(ProcessValues (data: Vec) -> super::Result<(), super::ProgramError>); + my_crate::sails::io_struct_impl!(Ping () -> String, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(ProcessValues (data: Vec) -> super::Result<(), super::ProgramError>, 1, ::INTERFACE_ID); } } @@ -1080,6 +1222,10 @@ pub mod my_complex_service { ) -> my_crate::sails::client::PendingCall; } pub struct MyComplexServiceImpl; + impl my_crate::sails::client::Identifiable for MyComplexServiceImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([86, 209, 202, 3, 195, 8, 232, 253]); + } impl MyComplexService for my_crate::sails::client::Service { @@ -1126,12 +1272,12 @@ pub mod my_complex_service { pub mod io { use super::*; - my_crate::sails::io_struct_impl!(GetActorIds (count: u32) -> Vec); - my_crate::sails::io_struct_impl!(GetData (key: String) -> super::Result); - my_crate::sails::io_struct_impl!(GetInfo () -> super::ProgramGlobalInfo); - my_crate::sails::io_struct_impl!(Initialize (start_data: super::ProgramGlobalInfo, max_size: u32) -> super::Result<(), super::ProgramError>); - my_crate::sails::io_struct_impl!(ProcessGenericData (input_data: super::GenericData, list_of_generics: Vec>, optional_generic_result: super::Option, >) -> super::GenericData); - my_crate::sails::io_struct_impl!(UpdateStatus (id: u64, new_status: super::ServiceStatus, metadata: super::Option) -> super::GenericResult); + my_crate::sails::io_struct_impl!(GetActorIds (count: u32) -> Vec, 0, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(GetData (key: String) -> super::Result, 1, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(GetInfo () -> super::ProgramGlobalInfo, 2, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(Initialize (start_data: super::ProgramGlobalInfo, max_size: u32) -> super::Result<(), super::ProgramError>, 3, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(ProcessGenericData (input_data: super::GenericData, list_of_generics: Vec>, optional_generic_result: super::Option, >) -> super::GenericData, 4, ::INTERFACE_ID); + my_crate::sails::io_struct_impl!(UpdateStatus (id: u64, new_status: super::ServiceStatus, metadata: super::Option) -> super::GenericResult, 5, ::INTERFACE_ID); } } @@ -1141,6 +1287,10 @@ pub mod rmrk_catalog { type Env: my_crate::sails::client::GearEnv; } pub struct RmrkCatalogImpl; + impl my_crate::sails::client::Identifiable for RmrkCatalogImpl { + const INTERFACE_ID: my_crate::sails::InterfaceId = + my_crate::sails::InterfaceId::from_bytes_8([197, 210, 70, 1, 134, 247, 35, 60]); + } impl RmrkCatalog for my_crate::sails::client::Service { diff --git a/rs/client-gen/tests/snapshots/generator__multiple_services.snap b/rs/client-gen/tests/snapshots/generator__multiple_services.snap index 15013c31..3b04c492 100644 --- a/rs/client-gen/tests/snapshots/generator__multiple_services.snap +++ b/rs/client-gen/tests/snapshots/generator__multiple_services.snap @@ -31,6 +31,10 @@ pub mod multiple { ) -> sails_rs::client::PendingCall; } pub struct MultipleImpl; + impl sails_rs::client::Identifiable for MultipleImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([2, 24, 22, 148, 109, 93, 75, 194]); + } impl Multiple for sails_rs::client::Service { type Env = E; fn do_that( @@ -50,8 +54,8 @@ pub mod multiple { pub mod io { use super::*; - sails_rs::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8); - sails_rs::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16); + sails_rs::io_struct_impl!(DoThat (p1: (u8, u32, )) -> u8, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(DoThis (p1: u32, p2: super::MyParam) -> u16, 1, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] @@ -70,6 +74,10 @@ pub mod named { fn that(&self, p1: u32) -> sails_rs::client::PendingCall; } pub struct NamedImpl; + impl sails_rs::client::Identifiable for NamedImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([81, 188, 228, 30, 50, 153, 227, 193]); + } impl Named for sails_rs::client::Service { type Env = E; fn that(&self, p1: u32) -> sails_rs::client::PendingCall { @@ -79,7 +87,7 @@ pub mod named { pub mod io { use super::*; - sails_rs::io_struct_impl!(That (p1: u32) -> String); + sails_rs::io_struct_impl!(That (p1: u32) -> String, 0, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/rs/client-gen/tests/snapshots/generator__rmrk_works.snap b/rs/client-gen/tests/snapshots/generator__rmrk_works.snap index f19b699a..dfd4a46c 100644 --- a/rs/client-gen/tests/snapshots/generator__rmrk_works.snap +++ b/rs/client-gen/tests/snapshots/generator__rmrk_works.snap @@ -9,6 +9,9 @@ extern crate std; #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct RmrkCatalogProgram; +impl RmrkCatalogProgram { + pub const ROUTE_ID_RMRK_CATALOG_SERVICE: u8 = 1; +} impl sails_rs::client::Program for RmrkCatalogProgram {} pub trait RmrkCatalog { type Env: sails_rs::client::GearEnv; @@ -21,7 +24,7 @@ impl RmrkCatalog for sails_rs::client::Actor sails_rs::client::Service { - self.service(stringify!(RmrkCatalogService)) + self.service(RmrkCatalogProgram::ROUTE_ID_RMRK_CATALOG_SERVICE) } } pub trait RmrkCatalogCtors { @@ -41,7 +44,7 @@ impl RmrkCatalogCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(New () -> ()); + sails_rs::io_struct_impl!(New () -> (), 0); } pub mod rmrk_catalog_service { @@ -128,6 +131,10 @@ pub mod rmrk_catalog_service { fn part(&self, part_id: u32) -> sails_rs::client::PendingCall; } pub struct RmrkCatalogServiceImpl; + impl sails_rs::client::Identifiable for RmrkCatalogServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([55, 233, 20, 71, 187, 19, 237, 60]); + } impl RmrkCatalogService for sails_rs::client::Service { @@ -184,14 +191,14 @@ pub mod rmrk_catalog_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(AddEquippables (part_id: u32, collection_ids: Vec) -> super::Result<(u32, Vec, ), super::Error, >); - sails_rs::io_struct_impl!(AddParts (parts: Vec<(u32, super::Part, )>) -> super::Result, super::Error, >); - sails_rs::io_struct_impl!(RemoveEquippable (part_id: u32, collection_id: ActorId) -> super::Result<(u32, ActorId, ), super::Error, >); - sails_rs::io_struct_impl!(RemoveParts (part_ids: Vec) -> super::Result, super::Error, >); - sails_rs::io_struct_impl!(ResetEquippables (part_id: u32) -> super::Result<(), super::Error, >); - sails_rs::io_struct_impl!(SetEquippablesToAll (part_id: u32) -> super::Result<(), super::Error, >); - sails_rs::io_struct_impl!(Equippable (part_id: u32, collection_id: ActorId) -> super::Result); - sails_rs::io_struct_impl!(Part (part_id: u32) -> super::Option); + sails_rs::io_struct_impl!(AddEquippables (part_id: u32, collection_ids: Vec) -> super::Result<(u32, Vec, ), super::Error, >, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(AddParts (parts: Vec<(u32, super::Part, )>) -> super::Result, super::Error, >, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(RemoveEquippable (part_id: u32, collection_id: ActorId) -> super::Result<(u32, ActorId, ), super::Error, >, 2, ::INTERFACE_ID); + sails_rs::io_struct_impl!(RemoveParts (part_ids: Vec) -> super::Result, super::Error, >, 3, ::INTERFACE_ID); + sails_rs::io_struct_impl!(ResetEquippables (part_id: u32) -> super::Result<(), super::Error, >, 4, ::INTERFACE_ID); + sails_rs::io_struct_impl!(SetEquippablesToAll (part_id: u32) -> super::Result<(), super::Error, >, 5, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Equippable (part_id: u32, collection_id: ActorId) -> super::Result, 6, ::INTERFACE_ID); + sails_rs::io_struct_impl!(Part (part_id: u32) -> super::Option, 7, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/rs/client-gen/tests/snapshots/generator__scope_resolution.snap b/rs/client-gen/tests/snapshots/generator__scope_resolution.snap index 156eb409..a50ca8c6 100644 --- a/rs/client-gen/tests/snapshots/generator__scope_resolution.snap +++ b/rs/client-gen/tests/snapshots/generator__scope_resolution.snap @@ -9,6 +9,9 @@ extern crate std; #[allow(unused_imports)] use sails_rs::{client::*, collections::*, prelude::*}; pub struct MyProgramProgram; +impl MyProgramProgram { + pub const ROUTE_ID_MY_SERVICE: u8 = 1; +} impl sails_rs::client::Program for MyProgramProgram {} pub trait MyProgram { type Env: sails_rs::client::GearEnv; @@ -17,7 +20,7 @@ pub trait MyProgram { impl MyProgram for sails_rs::client::Actor { type Env = E; fn my_service(&self) -> sails_rs::client::Service { - self.service(stringify!(MyService)) + self.service(MyProgramProgram::ROUTE_ID_MY_SERVICE) } } pub trait MyProgramCtors { @@ -35,7 +38,7 @@ impl MyProgramCtors pub mod io { use super::*; - sails_rs::io_struct_impl!(Init () -> ()); + sails_rs::io_struct_impl!(Init () -> (), 0); } #[derive(PartialEq, Clone, Debug, Encode, Decode, TypeInfo, ReflectHash)] #[codec(crate = sails_rs::scale_codec)] @@ -94,6 +97,10 @@ pub mod my_service { ) -> sails_rs::client::PendingCall; } pub struct MyServiceImpl; + impl sails_rs::client::Identifiable for MyServiceImpl { + const INTERFACE_ID: sails_rs::InterfaceId = + sails_rs::InterfaceId::from_bytes_8([253, 255, 66, 173, 41, 217, 46, 249]); + } impl MyService for sails_rs::client::Service { type Env = E; fn another_action( @@ -118,9 +125,9 @@ pub mod my_service { pub mod io { use super::*; - sails_rs::io_struct_impl!(AnotherAction (input: super::ServiceCommonType) -> u32); - sails_rs::io_struct_impl!(DoSomething (input: super::CommonType) -> u32); - sails_rs::io_struct_impl!(UseProgramType (input: super::ProgramOnlyType) -> bool); + sails_rs::io_struct_impl!(AnotherAction (input: super::ServiceCommonType) -> u32, 0, ::INTERFACE_ID); + sails_rs::io_struct_impl!(DoSomething (input: super::CommonType) -> u32, 1, ::INTERFACE_ID); + sails_rs::io_struct_impl!(UseProgramType (input: super::ProgramOnlyType) -> bool, 2, ::INTERFACE_ID); } #[cfg(feature = "with_mocks")] diff --git a/rs/ethexe/ethapp_with_events/tests/gtest.rs b/rs/ethexe/ethapp_with_events/tests/gtest.rs index a9330436..950d7286 100644 --- a/rs/ethexe/ethapp_with_events/tests/gtest.rs +++ b/rs/ethexe/ethapp_with_events/tests/gtest.rs @@ -4,6 +4,7 @@ use sails_rs::{ client::*, futures::StreamExt, gtest::{Program, System}, + meta::{ServiceMeta, SailsMessageHeader}, prelude::*, }; @@ -202,10 +203,14 @@ async fn ethapp_with_events_exposure_emit_works() { let (from, event_payload) = listener.next().await.unwrap(); assert_eq!(from, program_id); - let (route, event_name, p1, p2): (String, String, u32, String) = + let (header, p1, p2): (SailsMessageHeader, u32, String) = Decode::decode(&mut event_payload.as_slice()).unwrap(); - assert_eq!(route, "Svc1"); - assert_eq!(event_name, "DoThisEvent"); + assert_eq!( + header.interface_id(), + ethapp_with_events::SomeService::INTERFACE_ID + ); + assert_eq!(header.route_id(), 1); + assert_eq!(header.entry_id(), 0); assert_eq!(p1, 42); assert_eq!(p2, "hello"); } diff --git a/rs/ethexe/macros-tests/tests/service_tests.rs b/rs/ethexe/macros-tests/tests/service_tests.rs index d5446e59..3adc3c65 100644 --- a/rs/ethexe/macros-tests/tests/service_tests.rs +++ b/rs/ethexe/macros-tests/tests/service_tests.rs @@ -1,8 +1,9 @@ use sails_rs::{ - Encode, MessageId, Syscall, + MessageId, Syscall, alloy_primitives::B256, alloy_sol_types::SolValue, - gstd::services::{ExposureWithEvents as _, Service}, + gstd::services::{Exposure, ExposureWithEvents as _, Service}, + meta::{ServiceMeta, SailsMessageHeader}, }; mod service_with_basics; @@ -19,24 +20,30 @@ mod service_with_trait_bounds; async fn service_with_basics() { use service_with_basics::MyService; - const DO_THIS: &str = "DoThis"; let input = (false, 42u32, "correct".to_owned()).abi_encode_sequence(); - let exposure = MyService.expose(&[1, 2, 3]); + let exposure = MyService.expose(1); + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); // Check asyncness for `DoThis`. - assert!(exposure.check_asyncness(&DO_THIS.encode()).unwrap()); + assert!( + <::Exposure as Exposure>::check_asyncness( + header.interface_id(), + header.entry_id() + ) + .unwrap() + ); assert!( exposure - .try_handle_solidity(&DO_THIS.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .is_none() ); // act let (output, ..) = MyService - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&DO_THIS.encode(), &input) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); @@ -48,15 +55,15 @@ async fn service_with_basics() { async fn service_with_basics_with_encode_reply() { use service_with_basics::MyService; - const DO_THIS: &str = "DoThis"; let input = (true, 42u32, "correct".to_owned()).abi_encode_sequence(); let message_id = MessageId::from(123); Syscall::with_message_id(message_id); + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); // act let (output, ..) = MyService - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&DO_THIS.encode(), &input) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); @@ -70,7 +77,7 @@ async fn service_with_basics_with_encode_reply() { fn service_with_events() { use service_with_events::{MyEvents, MyServiceWithEvents}; - let mut exposure = MyServiceWithEvents(0).expose(&[1, 4, 2]); + let mut exposure = MyServiceWithEvents(0).expose(1); let mut emitter = exposure.emitter(); exposure.my_method(); @@ -83,17 +90,25 @@ fn service_with_events() { fn service_with_lifetimes_and_events() { use service_with_events_and_lifetimes::{MyEvents, MyGenericEventsService}; - const DO_THIS: &str = "DoThis"; let input = (false,).abi_encode_sequence(); let my_service = MyGenericEventsService::<'_, String>::default(); - let exposure = my_service.expose(&[1, 2, 3]); + let exposure = my_service.expose(1); let mut emitter = exposure.emitter(); - assert!(!exposure.check_asyncness(&DO_THIS.encode()).unwrap()); + let header = + SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); + // Check asyncness for `DoThis`. + assert!( + !<::Exposure as Exposure>::check_asyncness( + header.interface_id(), + header.entry_id() + ) + .unwrap() + ); let (output, ..) = exposure - .try_handle_solidity(&DO_THIS.encode(), input.as_slice()) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); @@ -111,42 +126,39 @@ fn service_with_extends() { extended::{EXTENDED_NAME_RESULT, Extended, NAME_RESULT}, }; - const NAME_METHOD: &str = "Name"; - const BASE_NAME_METHOD: &str = "BaseName"; - const EXTENDED_NAME_METHOD: &str = "ExtendedName"; let input = (false,).abi_encode_sequence(); - let extended_svc = Extended::new(Base).expose(&[1, 2, 3]); + let extended_svc = Extended::new(Base).expose(1); + // Extended::extended_name + let header = SailsMessageHeader::v1(Extended::INTERFACE_ID, 0, 1); + // Check asyncness of the service. assert!( - !extended_svc - .check_asyncness(&EXTENDED_NAME_METHOD.encode()) - .unwrap() - ); - - assert!( - !extended_svc - .check_asyncness(&BASE_NAME_METHOD.encode()) + !::Exposure::check_asyncness(header.interface_id(), header.entry_id()) .unwrap() ); let (output, ..) = extended_svc - .try_handle_solidity(&EXTENDED_NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); assert_eq!(Ok(EXTENDED_NAME_RESULT.to_owned()), result); - let extended_svc = Extended::new(Base).expose(&[1, 2, 3]); + let extended_svc = Extended::new(Base).expose(1); + // Base::base_name + let header = SailsMessageHeader::v1(Base::INTERFACE_ID, 0, 1); let (output, ..) = extended_svc - .try_handle_solidity(&BASE_NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); assert_eq!(Ok(BASE_NAME_RESULT.to_owned()), result); - let extended_svc = Extended::new(Base).expose(&[1, 2, 3]); + let extended_svc = Extended::new(Base).expose(1); + // Extended::name + let header = SailsMessageHeader::v1(Extended::INTERFACE_ID, 1, 1); let (output, ..) = extended_svc - .try_handle_solidity(&NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); @@ -157,14 +169,15 @@ fn service_with_extends() { fn service_with_lifecycles_and_generics() { use service_with_lifecycles_and_generics::MyGenericService; - const DO_THIS: &str = "DoThis"; let input = (false,).abi_encode_sequence(); let my_service = MyGenericService::<'_, String>::default(); + // SomeService::do_this + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); let (output, ..) = my_service - .expose(&[1, 2, 3]) - .try_handle_solidity(&DO_THIS.encode(), &input) + .expose(1) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); @@ -177,32 +190,35 @@ fn service_with_extends_and_lifetimes() { BASE_NAME_RESULT, BaseWithLifetime, EXTENDED_NAME_RESULT, ExtendedWithLifetime, NAME_RESULT, }; - const NAME_METHOD: &str = "Name"; - const BASE_NAME_METHOD: &str = "BaseName"; - const EXTENDED_NAME_METHOD: &str = "ExtendedName"; let input = (false,).abi_encode_sequence(); let int = 42u64; - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(&[1, 2, 3]); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); + // ExtendedWithLifetime::extended_name + let header = SailsMessageHeader::v1(ExtendedWithLifetime::INTERFACE_ID, 0, 1); let (output, ..) = extended_svc - .try_handle_solidity(&EXTENDED_NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); assert_eq!(Ok(EXTENDED_NAME_RESULT.to_owned()), result); - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(&[1, 2, 3]); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); + // BaseWithLifetime::base_name + let header = SailsMessageHeader::v1(BaseWithLifetime::INTERFACE_ID, 0, 1); let (output, ..) = extended_svc - .try_handle_solidity(&BASE_NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); assert_eq!(Ok(BASE_NAME_RESULT.to_owned()), result); - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(&[1, 2, 3]); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); + // ExtendedWithLifetime::name + let header = SailsMessageHeader::v1(ExtendedWithLifetime::INTERFACE_ID, 1, 1); let (output, ..) = extended_svc - .try_handle_solidity(&NAME_METHOD.encode(), &input) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); @@ -213,12 +229,12 @@ fn service_with_extends_and_lifetimes() { async fn service_with_export_unwrap_result() { use service_with_export_unwrap_result::MyService; - const DO_THIS: &str = "DoThis"; + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); let input = (false, 42u32, "correct").abi_encode_sequence(); let (output, ..) = MyService - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&DO_THIS.encode(), input.as_slice()) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); @@ -231,12 +247,13 @@ async fn service_with_export_unwrap_result() { async fn service_with_export_unwrap_result_panic() { use service_with_export_unwrap_result::MyService; - const PARSE: &str = "Parse"; + let header = SailsMessageHeader::v1(::INTERFACE_ID, 1, 1); + let input = (false, "not a number").abi_encode_sequence(); _ = MyService - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&PARSE.encode(), input.as_slice()) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); } @@ -245,12 +262,12 @@ async fn service_with_export_unwrap_result_panic() { async fn service_with_reply_with_value() { use service_with_reply_with_value::MyServiceWithReplyWithValue; - const DO_THIS: &str = "DoThis"; - + // MyServiceWithReplyWithValue::do_this + let header = SailsMessageHeader::v1(MyServiceWithReplyWithValue::INTERFACE_ID, 1, 1); let input = (false, 42u32, "correct".to_owned()).abi_encode_sequence(); let (output, value, ..) = MyServiceWithReplyWithValue - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&DO_THIS.encode(), input.as_slice()) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); @@ -264,12 +281,12 @@ async fn service_with_reply_with_value() { async fn service_with_reply_with_value_with_impl_from() { use service_with_reply_with_value::MyServiceWithReplyWithValue; - const DO_THAT: &str = "DoThat"; - + // MyServiceWithReplyWithValue::do_that + let header = SailsMessageHeader::v1(MyServiceWithReplyWithValue::INTERFACE_ID, 0, 1); let input = (false, 42u32, "correct".to_owned()).abi_encode_sequence(); let (output, value, ..) = MyServiceWithReplyWithValue - .expose(&[1, 2, 3]) - .try_handle_solidity_async(&DO_THAT.encode(), input.as_slice()) + .expose(1) + .try_handle_solidity_async(header.interface_id(), header.entry_id(), &input) .await .unwrap(); @@ -283,12 +300,17 @@ async fn service_with_reply_with_value_with_impl_from() { async fn service_with_trait_bounds() { use service_with_trait_bounds::MyServiceWithTraitBounds; - const DO_THIS: &str = "DoThis"; let input = (false,).abi_encode_sequence(); + // MyServiceWithTraitBounds::do_this + let header = SailsMessageHeader::v1( + ::INTERFACE_ID, + 0, + 1, + ); let (output, ..) = MyServiceWithTraitBounds::::default() - .expose(&[1, 2, 3]) - .try_handle_solidity(&DO_THIS.encode(), &input) + .expose(1) + .try_handle_solidity(header.interface_id(), header.entry_id(), &input) .unwrap(); let result = sails_rs::alloy_sol_types::SolValue::abi_decode(output.as_slice(), false); diff --git a/rs/ethexe/macros-tests/tests/service_with_events_and_lifetimes/mod.rs b/rs/ethexe/macros-tests/tests/service_with_events_and_lifetimes/mod.rs index ed315338..2fe97865 100644 --- a/rs/ethexe/macros-tests/tests/service_with_events_and_lifetimes/mod.rs +++ b/rs/ethexe/macros-tests/tests/service_with_events_and_lifetimes/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; #[derive(Default)] -pub(super) struct MyGenericEventsService<'l, T> { +pub(super) struct MyGenericEventsService<'l, T = String> { _t: Option, _a: PhantomData<&'l T>, } diff --git a/rs/ethexe/macros-tests/tests/service_with_lifecycles_and_generics/mod.rs b/rs/ethexe/macros-tests/tests/service_with_lifecycles_and_generics/mod.rs index 752ecf86..6948c329 100644 --- a/rs/ethexe/macros-tests/tests/service_with_lifecycles_and_generics/mod.rs +++ b/rs/ethexe/macros-tests/tests/service_with_lifecycles_and_generics/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; #[derive(Default)] -pub(super) struct MyGenericService<'a, T> { +pub(super) struct MyGenericService<'a, T = String> { _a: PhantomData<&'a T>, } diff --git a/rs/ethexe/macros-tests/tests/service_with_trait_bounds/mod.rs b/rs/ethexe/macros-tests/tests/service_with_trait_bounds/mod.rs index fcdfb65f..b5a18eba 100644 --- a/rs/ethexe/macros-tests/tests/service_with_trait_bounds/mod.rs +++ b/rs/ethexe/macros-tests/tests/service_with_trait_bounds/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; #[derive(Default)] -pub(super) struct MyServiceWithTraitBounds<'a, T> { +pub(super) struct MyServiceWithTraitBounds<'a, T = u32> { _a: PhantomData<&'a T>, } diff --git a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_basic.snap b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_basic.snap index 96fa4a53..ea8a6a8d 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_basic.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_basic.snap @@ -13,6 +13,11 @@ impl sails_rs::SailsEvent for MyEvent { } } } + fn entry_id(&self) -> u16 { + match self { + MyEvent::MyEvent1 => 0u16, + } + } fn skip_bytes() -> usize { 1 } diff --git a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_indexed.snap b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_indexed.snap index ed9a5194..81e43938 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_indexed.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_indexed.snap @@ -27,6 +27,13 @@ impl sails_rs::SailsEvent for Events { } } } + fn entry_id(&self) -> u16 { + match self { + Events::MyEvent1 { .. } => 0u16, + Events::MyEvent2(..) => 1u16, + Events::MyEvent3 => 2u16, + } + } fn skip_bytes() -> usize { 1 } diff --git a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_sails_rename.snap b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_sails_rename.snap index cf8b3803..8682bca3 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_sails_rename.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/eth_event__eth_event_sails_rename.snap @@ -27,6 +27,13 @@ impl sails_rename::SailsEvent for Events { } } } + fn entry_id(&self) -> u16 { + match self { + Events::MyEvent1 { .. } => 0u16, + Events::MyEvent2(..) => 1u16, + Events::MyEvent3 => 2u16, + } + } fn skip_bytes() -> usize { 1 } diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_ctors_meta_with_docs.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_ctors_meta_with_docs.snap index 93e748ad..4854cc68 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_ctors_meta_with_docs.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_ctors_meta_with_docs.snap @@ -20,7 +20,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -28,11 +27,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -40,11 +34,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -58,7 +47,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[12u8, 78u8, 101u8, 119u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "new", <<( bool, @@ -70,7 +60,8 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 78u8, 101u8, 119u8, 50u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 1u16, "new2", <<( bool, @@ -93,8 +84,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -108,15 +100,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -130,57 +118,101 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[12u8, 78u8, 101u8, 119u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - gstd::message_loop(async move { - let program = MyProgram::new(p1, p2).await; + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { PROGRAM = Some(program) }; + }); + Some(__encode_reply) + } + 1u16 => { + let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::new2(p2, p1); unsafe { PROGRAM = Some(program) }; - }); - return Some(__encode_reply); - } - if ctor == &[16u8, 78u8, 101u8, 119u8, 50u8] { - let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::new2(p2, p1); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_multiple_services_with_non_empty_routes.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_multiple_services_with_non_empty_routes.snap index e9e96195..415d0d41 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_multiple_services_with_non_empty_routes.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_multiple_services_with_non_empty_routes.snap @@ -18,7 +18,7 @@ impl MyProgram { let service = self.__service1(); let exposure = ::expose( service, - __ROUTE_SVC1.as_ref(), + 1u8, ); exposure } @@ -28,15 +28,11 @@ impl MyProgram { let service = self.__service2(); let exposure = ::expose( service, - __ROUTE_SERVICE2.as_ref(), + 2u8, ); exposure } } -const __ROUTE_SVC1: [u8; 5usize] = [16u8, 83u8, 118u8, 99u8, 49u8]; -const __ROUTE_SERVICE2: [u8; 9usize] = [ - 32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -48,16 +44,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -67,7 +57,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "create", <<( bool, @@ -78,16 +69,8 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ), ]; const SERVICES: &'static [sails_rs::solidity::ServiceExpo] = &[ - ( - "service2", - &[32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8] as &[u8], - ::METHODS, - ), - ( - "svc1", - &[16u8, 83u8, 118u8, 99u8, 49u8] as &[u8], - ::METHODS, - ), + ("svc1", 1u8, ::METHODS), + ("service2", 2u8, ::METHODS), ]; const METHODS_LEN: usize = ::METHODS .len() + ::METHODS.len(); @@ -100,8 +83,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -115,15 +99,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -137,44 +117,85 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::create(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::create(); + unsafe { PROGRAM = Some(program) }; + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 2usize + + sails_rs::meta::count_base_services::() + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >( + &[ + sails_rs::meta::BaseServiceMeta::new::(""), + sails_rs::meta::BaseServiceMeta::new::(""), + ], + ); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; - if route == &__ROUTE_SVC1 { + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + if route_idx == 1u8 { let mut service = program_ref.service1(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = ::Exposure::check_asyncness( + interface_id, + entry_id, + ) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async( + interface_id, + entry_id, + &input[4..], + ) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -190,7 +211,7 @@ pub mod wasm { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); @@ -205,15 +226,22 @@ pub mod wasm { } return; } - if route == &__ROUTE_SERVICE2 { + if route_idx == 2u8 { let mut service = program_ref.service2(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = ::Exposure::check_asyncness( + interface_id, + entry_id, + ) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async( + interface_id, + entry_id, + &input[4..], + ) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -229,7 +257,7 @@ pub mod wasm { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); @@ -246,87 +274,100 @@ pub mod wasm { } } } - if input.starts_with(&__ROUTE_SVC1) { - let mut service = program_ref.service1(); - let is_async = service - .check_asyncness(&input[__ROUTE_SVC1.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SVC1.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service1(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); - } - } else if input.starts_with(&__ROUTE_SERVICE2) { - let mut service = program_ref.service2(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE2.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE2.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + 2u8 => { + let svc = program_ref.service2(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_services_with_unwrap_result.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_services_with_unwrap_result.snap index 370cf033..9020dc9e 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_services_with_unwrap_result.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_services_with_unwrap_result.snap @@ -18,7 +18,7 @@ impl MyProgram { let service = self.__service1().unwrap(); let exposure = ::expose( service, - __ROUTE_SVC1.as_ref(), + 1u8, ); exposure } @@ -28,15 +28,11 @@ impl MyProgram { let service = self.__service2(); let exposure = ::expose( service, - __ROUTE_SERVICE2.as_ref(), + 2u8, ); exposure } } -const __ROUTE_SVC1: [u8; 5usize] = [16u8, 83u8, 118u8, 99u8, 49u8]; -const __ROUTE_SERVICE2: [u8; 9usize] = [ - 32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -48,16 +44,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -67,7 +57,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "create", <<( bool, @@ -78,16 +69,8 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ), ]; const SERVICES: &'static [sails_rs::solidity::ServiceExpo] = &[ - ( - "service2", - &[32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8] as &[u8], - ::METHODS, - ), - ( - "svc1", - &[16u8, 83u8, 118u8, 99u8, 49u8] as &[u8], - ::METHODS, - ), + ("svc1", 1u8, ::METHODS), + ("service2", 2u8, ::METHODS), ]; const METHODS_LEN: usize = ::METHODS .len() + ::METHODS.len(); @@ -100,8 +83,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -115,15 +99,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -137,44 +117,85 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::create(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::create(); + unsafe { PROGRAM = Some(program) }; + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 2usize + + sails_rs::meta::count_base_services::() + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >( + &[ + sails_rs::meta::BaseServiceMeta::new::(""), + sails_rs::meta::BaseServiceMeta::new::(""), + ], + ); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; - if route == &__ROUTE_SVC1 { + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + if route_idx == 1u8 { let mut service = program_ref.service1(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = ::Exposure::check_asyncness( + interface_id, + entry_id, + ) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async( + interface_id, + entry_id, + &input[4..], + ) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -190,7 +211,7 @@ pub mod wasm { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); @@ -205,15 +226,22 @@ pub mod wasm { } return; } - if route == &__ROUTE_SERVICE2 { + if route_idx == 2u8 { let mut service = program_ref.service2(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = ::Exposure::check_asyncness( + interface_id, + entry_id, + ) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async( + interface_id, + entry_id, + &input[4..], + ) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -229,7 +257,7 @@ pub mod wasm { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); @@ -246,87 +274,100 @@ pub mod wasm { } } } - if input.starts_with(&__ROUTE_SVC1) { - let mut service = program_ref.service1(); - let is_async = service - .check_asyncness(&input[__ROUTE_SVC1.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SVC1.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service1(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); - } - } else if input.starts_with(&__ROUTE_SERVICE2) { - let mut service = program_ref.service2(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE2.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE2.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + 2u8 => { + let svc = program_ref.service2(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_single_service_with_non_empty_route.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_single_service_with_non_empty_route.snap index 7fafa543..83b7b449 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_single_service_with_non_empty_route.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_for_single_service_with_non_empty_route.snap @@ -13,14 +13,11 @@ impl MyProgram { let service = self.__service(); let exposure = ::expose( service, - __ROUTE_SERVICE.as_ref(), + 1u8, ); exposure } } -const __ROUTE_SERVICE: [u8; 8usize] = [ - 28u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -30,16 +27,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -49,7 +40,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "create", <<( bool, @@ -60,11 +52,7 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ), ]; const SERVICES: &'static [sails_rs::solidity::ServiceExpo] = &[ - ( - "service", - &[28u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8] as &[u8], - ::METHODS, - ), + ("service", 1u8, ::METHODS), ]; const METHODS_LEN: usize = ::METHODS .len(); @@ -77,8 +65,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -92,15 +81,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -114,44 +99,79 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::create(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::create(); + unsafe { PROGRAM = Some(program) }; + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 1usize + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[sails_rs::meta::BaseServiceMeta::new::("")]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; - if route == &__ROUTE_SERVICE { + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + if route_idx == 1u8 { let mut service = program_ref.service(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = ::Exposure::check_asyncness( + interface_id, + entry_id, + ) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async( + interface_id, + entry_id, + &input[4..], + ) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -167,7 +187,7 @@ pub mod wasm { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); @@ -184,48 +204,59 @@ pub mod wasm { } } } - if input.starts_with(&__ROUTE_SERVICE) { - let mut service = program_ref.service(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_with_crate_path.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_with_crate_path.snap index 50daaf6b..e3d442a2 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_with_crate_path.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_handle_with_crate_path.snap @@ -14,16 +14,10 @@ impl sails_rename::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rename::gstd::InvocationIo; #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum ConstructorsMeta { @@ -33,7 +27,8 @@ mod meta_in_program { impl sails_rename::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rename::solidity::MethodExpo] = &[ ( - &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], + sails_rename::meta::InterfaceId::zero(), + 0u16, "create", <<( bool, @@ -56,8 +51,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rename::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rename::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -71,15 +67,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -93,38 +85,76 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rename::meta::InterfaceId::zero() { + sails_rename::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rename::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rename::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rename::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::create(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::create(); + unsafe { PROGRAM = Some(program) }; + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rename::meta::InterfaceId, u8)] = &sails_rename::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_multiple_ctors.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_multiple_ctors.snap index 003513d9..be50da9f 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_multiple_ctors.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_multiple_ctors.snap @@ -17,7 +17,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -25,11 +24,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -37,11 +31,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -52,7 +41,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[12u8, 78u8, 101u8, 119u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "new", <<( bool, @@ -64,7 +54,8 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 78u8, 101u8, 119u8, 50u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 1u16, "new2", <<( bool, @@ -87,8 +78,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -102,15 +94,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -124,57 +112,101 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[12u8, 78u8, 101u8, 119u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - gstd::message_loop(async move { - let program = MyProgram::new(p1, p2).await; + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { PROGRAM = Some(program) }; + }); + Some(__encode_reply) + } + 1u16 => { + let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::new2(p2, p1); unsafe { PROGRAM = Some(program) }; - }); - return Some(__encode_reply); - } - if ctor == &[16u8, 78u8, 101u8, 119u8, 50u8] { - let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::new2(p2, p1); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_no_ctor.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_no_ctor.snap index 0695a862..3c41541d 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_no_ctor.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_no_ctor.snap @@ -14,16 +14,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -33,7 +27,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "create", <<( bool, @@ -54,8 +49,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -69,15 +65,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -91,38 +83,76 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::create(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::create(); + unsafe { PROGRAM = Some(program) }; + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_single_ctor.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_single_ctor.snap index 1582604e..9aba9e8c 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_single_ctor.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_for_single_ctor.snap @@ -14,7 +14,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -22,11 +21,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -36,7 +30,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[12u8, 78u8, 101u8, 119u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "new", <<( bool, @@ -59,8 +54,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -74,15 +70,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -96,42 +88,80 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); } - }); - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } + } + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[12u8, 78u8, 101u8, 119u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - gstd::message_loop(async move { - let program = MyProgram::new(p1, p2).await; - unsafe { PROGRAM = Some(program) }; - }); - return Some(__encode_reply); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { PROGRAM = Some(program) }; + }); + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_with_unwrap_result.snap b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_with_unwrap_result.snap index 5021bbaf..bbbe6714 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_with_unwrap_result.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/program_insta__generates_init_with_unwrap_result.snap @@ -19,7 +19,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -27,11 +26,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -39,11 +33,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -54,7 +43,8 @@ mod meta_in_program { impl sails_rs::solidity::ProgramSignature for MyProgram { const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[12u8, 78u8, 101u8, 119u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 0u16, "new", <<( bool, @@ -66,7 +56,8 @@ impl sails_rs::solidity::ProgramSignature for MyProgram { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 78u8, 101u8, 119u8, 50u8] as &[u8], + sails_rs::meta::InterfaceId::zero(), + 1u16, "new2", <<( bool, @@ -89,8 +80,9 @@ const __METHOD_SIGS: [[u8; 4]; ::method_sigs(); const __METHOD_ROUTES: [( - &'static [u8], - &'static [u8], + sails_rs::meta::InterfaceId, + u16, + u8, ); ::METHODS_LEN] = sails_rs::solidity::ConstProgramMeta::< MyProgram, >::method_routes(); @@ -104,15 +96,11 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = ::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity( - ctor_route, - &input[4..], - ) { + let (_, entry_id, ..) = ::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &input[4..]) { if encode_reply { let output = [ __CTOR_CALLBACK_SIGS[idx].as_slice(), @@ -126,57 +114,101 @@ pub mod wasm { } } } - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await.unwrap(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await.unwrap(); + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1).unwrap(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1).unwrap(); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - if ctor == &[12u8, 78u8, 101u8, 119u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - gstd::message_loop(async move { - let program = MyProgram::new(p1, p2).await.unwrap(); + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await.unwrap(); + unsafe { PROGRAM = Some(program) }; + }); + Some(__encode_reply) + } + 1u16 => { + let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .expect("Failed to decode request"); + let program = MyProgram::new2(p2, p1).unwrap(); unsafe { PROGRAM = Some(program) }; - }); - return Some(__encode_reply); - } - if ctor == &[16u8, 78u8, 101u8, 119u8, 50u8] { - let (__encode_reply, p2, p1): (bool, String, u32) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .expect("Failed to decode request"); - let program = MyProgram::new2(p2, p1).unwrap(); - unsafe { PROGRAM = Some(program) }; - return Some(__encode_reply); + Some(__encode_reply) + } + _ => None, } - None } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; + } + } + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } } - { gstd::unknown_input_panic("Unexpected service", &input) }; } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_allow_attrs.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_allow_attrs.snap index 0c215c3b..d682b471 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_allow_attrs.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_allow_attrs.snap @@ -3,27 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -49,191 +55,216 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(p1, p2).await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(p1, p2).await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -241,7 +272,8 @@ mod some_service_meta { impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -254,7 +286,8 @@ impl sails_rs::solidity::ServiceSignature for SomeService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_basics.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_basics.snap index d849d03a..2a63d68c 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_basics.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_basics.snap @@ -3,27 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -46,191 +52,216 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(p1, p2).await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(p1, p2).await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -238,7 +269,8 @@ mod some_service_meta { impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -251,7 +283,8 @@ impl sails_rs::solidity::ServiceSignature for SomeService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_crate_path.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_crate_path.snap index e19a7ac5..e5010ef6 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_crate_path.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_crate_path.snap @@ -3,27 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rename::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rename::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -46,196 +52,216 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rename::gstd::services::{Exposure, Service}; + use sails_rename::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rename::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rename::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rename::gstd::services::{Exposure, Service}; + use sails_rename::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rename::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rename::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rename::Vec, u128, bool)> { use sails_rename::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rename::alloy_primitives::B256::new( - sails_rename::gstd::Syscall::message_id().into_bytes(), - ); - sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rename::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rename::alloy_primitives::B256::new( + sails_rename::gstd::Syscall::message_id().into_bytes(), + ); + sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rename::Vec, u128, bool)> { use sails_rename::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(p1, p2).await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rename::alloy_primitives::B256::new( - sails_rename::gstd::Syscall::message_id().into_bytes(), - ); - sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rename::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rename::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(p1, p2).await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rename::alloy_primitives::B256::new( + sails_rename::gstd::Syscall::message_id().into_bytes(), + ); + sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rename::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rename::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rename::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [( - &'static str, - sails_rename::meta::AnyServiceMetaFn, - )] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rename::meta::InterfaceId = { - let mut final_hash = sails_rename::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rename::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update( - &::HASH, - ); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rename::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rename::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rename::{Decode, TypeInfo}; - use sails_rename::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rename::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rename::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rename::meta::InterfaceId = { + let mut final_hash = sails_rename::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rename::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rename::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rename::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rename::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rename::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rename::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rename::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -243,7 +269,8 @@ mod some_service_meta { impl sails_rename::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rename::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -256,7 +283,8 @@ impl sails_rename::solidity::ServiceSignature for SomeService { ) as sails_rename::alloy_sol_types::SolValue>::SolType as sails_rename::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_docs.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_docs.snap index cd97297c..ec49f523 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_docs.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_docs.snap @@ -3,27 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -49,194 +55,219 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(p1, p2).await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(p1, p2).await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { /// `DoThis` command /// Second line DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { /// `This` query This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -244,7 +275,8 @@ mod some_service_meta { impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -257,7 +289,8 @@ impl sails_rs::solidity::ServiceSignature for SomeService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_events.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_events.snap index f88d3b46..90e11b6a 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_events.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_events.snap @@ -3,31 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct MyServiceWithEventsExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for MyServiceWithEventsExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = my_service_with_events_meta::__DoThisParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = my_service_with_events_meta::__ThisParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -54,110 +56,153 @@ impl MyServiceWithEventsExposure { pub fn this(&self) -> bool { true } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = my_service_with_events_meta::__DoThisParams::decode_params( - input, - ) { - let result = self.do_this(); - let value = 0u128; - if !my_service_with_events_meta::__DoThisParams::is_empty_tuple::() { - my_service_with_events_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = my_service_with_events_meta::__ThisParams::decode_params( - input, - ) { - let result = self.this(); - let value = 0u128; - if !my_service_with_events_meta::__ThisParams::is_empty_tuple::() { - my_service_with_events_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: my_service_with_events_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: my_service_with_events_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + 1u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - None + if interface_id + == ::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: MyEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -170,78 +215,60 @@ impl MyServiceWithEventsExposure { } impl sails_rs::gstd::services::Service for MyServiceWithEvents { type Exposure = MyServiceWithEventsExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for MyServiceWithEvents { - type CommandsMeta = my_service_with_events_meta::CommandsMeta; - type QueriesMeta = my_service_with_events_meta::QueriesMeta; - type EventsMeta = my_service_with_events_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod my_service_with_events_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::MyServiceWithEvents { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash.update(&sails_rs::hash_fn!(query This() -> bool)); + final_hash = final_hash + .update(&::HASH); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams {} - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = MyEvents; @@ -249,7 +276,8 @@ mod my_service_with_events_meta { impl sails_rs::solidity::ServiceSignature for MyServiceWithEvents { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -260,7 +288,8 @@ impl sails_rs::solidity::ServiceSignature for MyServiceWithEvents { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_export.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_export.snap index af5e525f..d480af87 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_export.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_export.snap @@ -3,29 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoSomethingParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -52,205 +56,220 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoSomethingParams::decode_params( - input, - ) { - let result = self.do_this(request.p1, request.p2).await.unwrap(); - let value = 0u128; - if !some_service_meta::__DoSomethingParams::is_empty_tuple::< - (u32, String), - >() { - some_service_meta::__DoSomethingParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoSomethingParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await.unwrap(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<(u32, String)>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method - == &[ - 44u8, 68u8, 111u8, 83u8, 111u8, 109u8, 101u8, 116u8, 104u8, 105u8, 110u8, - 103u8, - ] + if interface_id + == ::INTERFACE_ID { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(p1, p2).await.unwrap(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(p1, p2).await.unwrap(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoSomething".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<(u32, String) as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update( + &sails_rs::hash_fn!( + command DoSomething(u32, String) -> (u32, String) + ), + ); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoSomethingParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoSomethingParams { - const ROUTE: &'static [u8] = &[ - 44u8, 68u8, 111u8, 83u8, 111u8, 109u8, 101u8, 116u8, 104u8, 105u8, 110u8, - 103u8, - ]; + impl sails_rs::gstd::InvocationIo for __DoSomethingParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoSomething(__DoSomethingParams, (u32, String)), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -258,10 +277,8 @@ mod some_service_meta { impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[ - 44u8, 68u8, 111u8, 83u8, 111u8, 109u8, 101u8, 116u8, 104u8, 105u8, 110u8, - 103u8, - ] as &[u8], + ::INTERFACE_ID, + 0u16, "DoSomething", <<( bool, @@ -274,7 +291,8 @@ impl sails_rs::solidity::ServiceSignature for SomeService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends.snap index d654bdd6..d46bc340 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends.snap @@ -3,34 +3,44 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -63,205 +73,247 @@ impl SomeServiceExposure { pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(); - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if base_services.0.expose(self.route).try_handle(input, result_handler).is_some() - { - return Some(()); - } - if base_services.1.expose(self.route).try_handle(input, result_handler).is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID { - return Some(()); + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services.0, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); + } + if sails_rs::gstd::services::Service::expose(base_services.1, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); + } + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if base_services - .0 - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() - { - return Some(()); - } - if base_services - .1 - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID { - return Some(()); + match entry_id { + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services.0, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + if sails_rs::gstd::services::Service::expose(base_services.1, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if let Some(result) = base_services - .0 - .expose(self.route) - .try_handle_solidity(method, input) + if interface_id + == ::INTERFACE_ID { - return Some(result); - } - if let Some(result) = base_services - .1 - .expose(self.route) - .try_handle_solidity(method, input) - { - return Some(result); + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if let Some(result) = base_services + .0 + .expose(self.route_idx) + .try_handle_solidity(interface_id, entry_id, input) + { + return Some(result); + } + if let Some(result) = base_services + .1 + .expose(self.route_idx) + .try_handle_solidity(interface_id, entry_id, input) + { + return Some(result); + } + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if let Some(result) = base_services - .0 - .expose(self.route) - .try_handle_solidity_async(method, input) - .await + if interface_id + == ::INTERFACE_ID { - return Some(result); - } - if let Some(result) = base_services - .1 - .expose(self.route) - .try_handle_solidity_async(method, input) - .await - { - return Some(result); + match entry_id { + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if let Some(result) = base_services + .0 + .expose(self.route_idx) + .try_handle_solidity_async(interface_id, entry_id, input) + .await + { + return Some(result); + } + if let Some(result) = base_services + .1 + .expose(self.route_idx) + .try_handle_solidity_async(interface_id, entry_id, input) + .await + { + return Some(result); + } + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ - ("ExtendedService1", sails_rs::meta::AnyServiceMeta::new::), - ("ExtendedService2", sails_rs::meta::AnyServiceMeta::new::), - ]; - const ASYNC: bool = ::ASYNC - || ::ASYNC; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::INTERFACE_ID.0); - final_hash = final_hash - .update(&::INTERFACE_ID.0); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[ + sails_rs::meta::BaseServiceMeta::new::< + super::ExtendedService1, + >("ExtendedService1"), + sails_rs::meta::BaseServiceMeta::new::< + super::ExtendedService2, + >("ExtendedService2"), + ]; + const ASYNC: bool = ::ASYNC + || ::ASYNC; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; } impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = sails_rs::const_concat_slices!( - < sails_rs::solidity::MethodExpo >, & [(& [24u8, 68u8, 111u8, 84u8, 104u8, 105u8, - 115u8] as & [u8], "DoThis", << (bool,) as sails_rs::alloy_sol_types::SolValue > - ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME, << + < sails_rs::solidity::MethodExpo >, & [(< SomeService as + sails_rs::meta::ServiceMeta > ::INTERFACE_ID, 0u16, "DoThis", << (bool,) as + sails_rs::alloy_sol_types::SolValue > ::SolType as + sails_rs::alloy_sol_types::SolType > ::SOL_NAME, << (sails_rs::alloy_primitives::B256, u32) as sails_rs::alloy_sol_types::SolValue > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME,),], < ExtendedService1 as sails_rs::solidity::ServiceSignature > ::METHODS, < diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends_and_lifetimes.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends_and_lifetimes.snap index 65a61073..0877b29b 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends_and_lifetimes.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_extends_and_lifetimes.snap @@ -3,36 +3,39 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct ExtendedWithLifetimeExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for ExtendedWithLifetimeExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = extended_with_lifetime_meta::__ExtendedNameParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = extended_with_lifetime_meta::__NameParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + _ => None, + } + } else { + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + None } - None } } impl core::ops::Deref for ExtendedWithLifetimeExposure { @@ -63,239 +66,270 @@ impl<'a> ExtendedWithLifetimeExposure> { pub fn name(&self) -> String { "extended".to_string() } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = extended_with_lifetime_meta::__ExtendedNameParams::decode_params( - input, - ) { - let result = self.extended_name(); - let value = 0u128; - if !extended_with_lifetime_meta::__ExtendedNameParams::is_empty_tuple::< - String, - >() { - extended_with_lifetime_meta::__ExtendedNameParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: extended_with_lifetime_meta::__ExtendedNameParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.extended_name(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: extended_with_lifetime_meta::__NameParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.name(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); - } - if let Ok(request) = extended_with_lifetime_meta::__NameParams::decode_params( - input, - ) { - let result = self.name(); - let value = 0u128; - if !extended_with_lifetime_meta::__NameParams::is_empty_tuple::() { - extended_with_lifetime_meta::__NameParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + } else { + let base_services: (BaseWithLifetime<'a>) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); } - return Some(()); + None } - let base_services: (BaseWithLifetime<'a>) = self.inner.into(); - if base_services.expose(self.route).try_handle(input, result_handler).is_some() { - return Some(()); - } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (BaseWithLifetime<'a>) = self.inner.into(); - if base_services - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID { - return Some(()); + match entry_id { + _ => None, + } + } else { + let base_services: (BaseWithLifetime<'a>) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method - == &[ - 48u8, 69u8, 120u8, 116u8, 101u8, 110u8, 100u8, 101u8, 100u8, 78u8, 97u8, - 109u8, 101u8, - ] - { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.extended_name(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - if method == &[16u8, 78u8, 97u8, 109u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.name(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - let base_services: (BaseWithLifetime<'a>) = self.inner.into(); - if let Some(result) = base_services - .expose(self.route) - .try_handle_solidity(method, input) + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID { - return Some(result); + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.extended_name(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + 1u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.name(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + let base_services: (BaseWithLifetime<'a>) = self.inner.into(); + if let Some(result) = base_services + .expose(self.route_idx) + .try_handle_solidity(interface_id, entry_id, input) + { + return Some(result); + } + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (BaseWithLifetime<'a>) = self.inner.into(); - if let Some(result) = base_services - .expose(self.route) - .try_handle_solidity_async(method, input) - .await + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID { - return Some(result); + match entry_id { + _ => None, + } + } else { + let base_services: (BaseWithLifetime<'a>) = self.inner.into(); + if let Some(result) = base_services + .expose(self.route_idx) + .try_handle_solidity_async(interface_id, entry_id, input) + .await + { + return Some(result); + } + None } - None } } impl<'a> sails_rs::gstd::services::Service for ExtendedWithLifetime<'a> { type Exposure = ExtendedWithLifetimeExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a> sails_rs::meta::ServiceMeta for ExtendedWithLifetime<'a> { - type CommandsMeta = extended_with_lifetime_meta::CommandsMeta; - type QueriesMeta = extended_with_lifetime_meta::QueriesMeta; - type EventsMeta = extended_with_lifetime_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ - ("BaseWithLifetime", sails_rs::meta::AnyServiceMeta::new::), - ]; - const ASYNC: bool = ::ASYNC; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("ExtendedName".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("Name".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::INTERFACE_ID.0); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod extended_with_lifetime_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a> sails_rs::meta::ServiceMeta for super::ExtendedWithLifetime<'a> { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[ + sails_rs::meta::BaseServiceMeta::new::< + super::BaseWithLifetime, + >("BaseWithLifetime"), + ]; + const ASYNC: bool = ::ASYNC; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query ExtendedName() -> String)); + final_hash = final_hash.update(&sails_rs::hash_fn!(query Name() -> String)); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ExtendedNameParams {} - impl InvocationIo for __ExtendedNameParams { - const ROUTE: &'static [u8] = &[ - 48u8, 69u8, 120u8, 116u8, 101u8, 110u8, 100u8, 101u8, 100u8, 78u8, 97u8, - 109u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __ExtendedNameParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __NameParams {} - impl InvocationIo for __NameParams { - const ROUTE: &'static [u8] = &[16u8, 78u8, 97u8, 109u8, 101u8]; + impl sails_rs::gstd::InvocationIo for __NameParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { ExtendedName(__ExtendedNameParams, String), Name(__NameParams, String), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; } impl<'a> sails_rs::solidity::ServiceSignature for ExtendedWithLifetime<'a> { const METHODS: &'static [sails_rs::solidity::MethodExpo] = sails_rs::const_concat_slices!( - < sails_rs::solidity::MethodExpo >, & [(& [48u8, 69u8, 120u8, 116u8, 101u8, - 110u8, 100u8, 101u8, 100u8, 78u8, 97u8, 109u8, 101u8] as & [u8], "ExtendedName", - << (bool,) as sails_rs::alloy_sol_types::SolValue > ::SolType as + < sails_rs::solidity::MethodExpo >, & [(< ExtendedWithLifetime as + sails_rs::meta::ServiceMeta > ::INTERFACE_ID, 0u16, "ExtendedName", << (bool,) as + sails_rs::alloy_sol_types::SolValue > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME, << (sails_rs::alloy_primitives::B256, String) as sails_rs::alloy_sol_types::SolValue - > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME,), (& [16u8, 78u8, - 97u8, 109u8, 101u8] as & [u8], "Name", << (bool,) as - sails_rs::alloy_sol_types::SolValue > ::SolType as + > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME,), (< + ExtendedWithLifetime as sails_rs::meta::ServiceMeta > ::INTERFACE_ID, 1u16, + "Name", << (bool,) as sails_rs::alloy_sol_types::SolValue > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME, << (sails_rs::alloy_primitives::B256, String) as sails_rs::alloy_sol_types::SolValue > ::SolType as sails_rs::alloy_sol_types::SolType > ::SOL_NAME,),], < diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_events.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_events.snap index 203de834..7b5a73bd 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_events.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_events.snap @@ -3,26 +3,32 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct MyGenericEventsServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for MyGenericEventsServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = my_generic_events_service_meta::__DoThisParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -48,76 +54,127 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = my_generic_events_service_meta::__DoThisParams::decode_params( - input, - ) { - let result = self.do_this(); - let value = 0u128; - if !my_generic_events_service_meta::__DoThisParams::is_empty_tuple::() { - my_generic_events_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: my_generic_events_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - None + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: MyEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -133,61 +190,51 @@ where T: Clone, { type Exposure = MyGenericEventsServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a, T> sails_rs::meta::ServiceMeta for MyGenericEventsService<'a, T> -where - T: Clone, -{ - type CommandsMeta = my_generic_events_service_meta::CommandsMeta; - type QueriesMeta = my_generic_events_service_meta::QueriesMeta; - type EventsMeta = my_generic_events_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod my_generic_events_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a, T> sails_rs::meta::ServiceMeta for super::MyGenericEventsService<'a, T> + where + T: Clone, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update(&::HASH); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = MyEvents; @@ -198,7 +245,8 @@ where { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_generics.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_generics.snap index 0ab8a7f9..9eb67540 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_generics.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_lifetimes_and_generics.snap @@ -3,24 +3,32 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -43,74 +51,135 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(); - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - None + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } } impl<'a, 'b, T, U> sails_rs::gstd::services::Service for SomeService<'a, 'b, T, U> @@ -119,60 +188,50 @@ where U: Iterator, { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a, 'b, T, U> sails_rs::meta::ServiceMeta for SomeService<'a, 'b, T, U> -where - T: Clone, - U: Iterator, -{ - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a, 'b, T, U> sails_rs::meta::ServiceMeta for super::SomeService<'a, 'b, T, U> + where + T: Clone, + U: Iterator, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -184,7 +243,8 @@ where { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_methods_with_lifetimes.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_methods_with_lifetimes.snap index a6fa0472..06194f48 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_methods_with_lifetimes.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_methods_with_lifetimes.snap @@ -3,46 +3,36 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct ReferenceServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for ReferenceServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = reference_service_meta::__AddByteParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__BakedParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__FirstByteParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__IncrParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__LastByteParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + 2u16 => Some(false), + 3u16 => Some(true), + 4u16 => Some(true), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for ReferenceServiceExposure { @@ -83,374 +73,367 @@ impl ReferenceServiceExposure { pub async fn last_byte<'a>(&self) -> Option<&'a u8> { unsafe { BYTES.last() } } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = reference_service_meta::__AddByteParams::decode_params( - input, - ) { - let result = self.add_byte(request.byte); - let value = 0u128; - if !reference_service_meta::__AddByteParams::is_empty_tuple::< - &'static [u8], - >() { - reference_service_meta::__AddByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__BakedParams::decode_params( - input, - ) { - let result = self.baked(); - let value = 0u128; - if !reference_service_meta::__BakedParams::is_empty_tuple::<&'static str>() { - reference_service_meta::__BakedParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__IncrParams::decode_params(input) { - let result = self.incr(); - let value = 0u128; - if !reference_service_meta::__IncrParams::is_empty_tuple::< - &'static ReferenceCount, - >() { - reference_service_meta::__IncrParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: reference_service_meta::__AddByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.add_byte(request.byte); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static [u8]>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: reference_service_meta::__IncrParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.incr(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static ReferenceCount>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 2u16 => { + let request: reference_service_meta::__BakedParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.baked(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static str>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = reference_service_meta::__FirstByteParams::decode_params( - input, - ) { - let result = self.first_byte().await; - let value = 0u128; - if !reference_service_meta::__FirstByteParams::is_empty_tuple::< - Option<&'static u8>, - >() { - reference_service_meta::__FirstByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__LastByteParams::decode_params( - input, - ) { - let result = self.last_byte().await; - let value = 0u128; - if !reference_service_meta::__LastByteParams::is_empty_tuple::< - Option<&'static u8>, - >() { - reference_service_meta::__LastByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 3u16 => { + let request: reference_service_meta::__FirstByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.first_byte().await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 4u16 => { + let request: reference_service_meta::__LastByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.last_byte().await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[28u8, 65u8, 100u8, 100u8, 66u8, 121u8, 116u8, 101u8] { - let (__encode_reply, byte): (bool, u8) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.add_byte(byte); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - if method == &[20u8, 66u8, 97u8, 107u8, 101u8, 100u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.baked(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - if method == &[16u8, 73u8, 110u8, 99u8, 114u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.incr(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, byte): (bool, u8) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.add_byte(byte); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + 1u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.incr(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + 2u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.baked(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[36u8, 70u8, 105u8, 114u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8] + if interface_id + == ::INTERFACE_ID { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.first_byte().await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); - } - if method == &[32u8, 76u8, 97u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.last_byte().await; - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + match entry_id { + 3u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.first_byte().await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + 4u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.last_byte().await; + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for ReferenceService { type Exposure = ReferenceServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for ReferenceService { - type CommandsMeta = reference_service_meta::CommandsMeta; - type QueriesMeta = reference_service_meta::QueriesMeta; - type EventsMeta = reference_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("AddByte".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static [u8] as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("Incr".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static ReferenceCount as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("Baked".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static str as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("FirstByte".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash +mod reference_service_meta { + use super::*; + impl sails_rs::meta::ServiceMeta for super::ReferenceService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command AddByte(u8) -> & 'static [u8])); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command Incr() -> & 'static ReferenceCount)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query Baked() -> & 'static str)); + final_hash = final_hash .update( - & as sails_rs::sails_reflect_hash::ReflectHash>::HASH, + &sails_rs::hash_fn!(query FirstByte() -> Option < & 'static u8 >), ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("LastByte".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash + final_hash = final_hash .update( - & as sails_rs::sails_reflect_hash::ReflectHash>::HASH, + &sails_rs::hash_fn!(query LastByte() -> Option < & 'static u8 >), ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} -mod reference_service_meta { - use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __AddByteParams { pub(super) byte: u8, } - impl InvocationIo for __AddByteParams { - const ROUTE: &'static [u8] = &[ - 28u8, 65u8, 100u8, 100u8, 66u8, 121u8, 116u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __AddByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __BakedParams {} - impl InvocationIo for __BakedParams { - const ROUTE: &'static [u8] = &[20u8, 66u8, 97u8, 107u8, 101u8, 100u8]; + pub struct __IncrParams {} + impl sails_rs::gstd::InvocationIo for __IncrParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __FirstByteParams {} - impl InvocationIo for __FirstByteParams { - const ROUTE: &'static [u8] = &[ - 36u8, 70u8, 105u8, 114u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8, - ]; + pub struct __BakedParams {} + impl sails_rs::gstd::InvocationIo for __BakedParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 2u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __IncrParams {} - impl InvocationIo for __IncrParams { - const ROUTE: &'static [u8] = &[16u8, 73u8, 110u8, 99u8, 114u8]; + pub struct __FirstByteParams {} + impl sails_rs::gstd::InvocationIo for __FirstByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 3u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __LastByteParams {} - impl InvocationIo for __LastByteParams { - const ROUTE: &'static [u8] = &[ - 32u8, 76u8, 97u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __LastByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 4u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { AddByte(__AddByteParams, &'static [u8]), Incr(__IncrParams, &'static ReferenceCount), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { Baked(__BakedParams, &'static str), FirstByte(__FirstByteParams, Option<&'static u8>), LastByte(__LastByteParams, Option<&'static u8>), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -458,7 +441,8 @@ mod reference_service_meta { impl sails_rs::solidity::ServiceSignature for ReferenceService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[28u8, 65u8, 100u8, 100u8, 66u8, 121u8, 116u8, 101u8] as &[u8], + ::INTERFACE_ID, + 0u16, "AddByte", <<( bool, @@ -470,41 +454,44 @@ impl sails_rs::solidity::ServiceSignature for ReferenceService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[20u8, 66u8, 97u8, 107u8, 101u8, 100u8] as &[u8], - "Baked", + ::INTERFACE_ID, + 1u16, + "Incr", <<( bool, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, <<( sails_rs::alloy_primitives::B256, - &'static str, + &'static ReferenceCount, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[36u8, 70u8, 105u8, 114u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8] - as &[u8], - "FirstByte", + ::INTERFACE_ID, + 2u16, + "Baked", <<( bool, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, <<( sails_rs::alloy_primitives::B256, - Option<&'a u8>, + &'static str, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 73u8, 110u8, 99u8, 114u8] as &[u8], - "Incr", + ::INTERFACE_ID, + 3u16, + "FirstByte", <<( bool, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, <<( sails_rs::alloy_primitives::B256, - &'static ReferenceCount, + Option<&'a u8>, ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[32u8, 76u8, 97u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8] as &[u8], + ::INTERFACE_ID, + 4u16, "LastByte", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_reply_with_value.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_reply_with_value.snap index 5451e5b1..d1abde1e 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_reply_with_value.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_reply_with_value.snap @@ -3,27 +3,33 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -46,194 +52,222 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let command_reply: CommandReply = self - .do_this(request.p1, request.p2) - .await - .into(); - let (result, value) = command_reply.to_tuple(); - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let command_reply: CommandReply = self + .do_this(request.p1, request.p2) + .await + .into(); + let (result, value) = command_reply.to_tuple(); + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[16u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.this(p1); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let (__encode_reply, p1): (bool, bool) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.this(p1); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let command_reply: CommandReply = self.do_this(p1, p2).await.into(); - let (result, value) = command_reply.to_tuple(); - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply, p1, p2): (bool, u32, String) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let command_reply: CommandReply = self + .do_this(p1, p2) + .await + .into(); + let (result, value) = command_reply.to_tuple(); + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; @@ -241,7 +275,8 @@ mod some_service_meta { impl sails_rs::solidity::ServiceSignature for SomeService { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, @@ -254,7 +289,8 @@ impl sails_rs::solidity::ServiceSignature for SomeService { ) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 1u16, "This", <<( bool, diff --git a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_special_lifetimes_and_events.snap b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_special_lifetimes_and_events.snap index d7977124..a7142626 100644 --- a/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_special_lifetimes_and_events.snap +++ b/rs/ethexe/macros-tests/tests/snapshots/service_insta__works_with_special_lifetimes_and_events.snap @@ -3,26 +3,32 @@ source: macros-tests/tests/service_insta.rs expression: result --- pub struct MyGenericEventsServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for MyGenericEventsServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = my_generic_events_service_meta::__DoThisParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -48,76 +54,131 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = my_generic_events_service_meta::__DoThisParams::decode_params( - input, - ) { - let result = self.do_this(); - let value = 0u128; - if !my_generic_events_service_meta::__DoThisParams::is_empty_tuple::() { - my_generic_events_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: my_generic_events_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn try_handle_solidity( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { - let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( - input, - false, - ) - .ok()?; - let result = self.do_this(); - let value = 0u128; - let output = if __encode_reply { - let message_id = sails_rs::alloy_primitives::B256::new( - sails_rs::gstd::Syscall::message_id().into_bytes(), - ); - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( - &(message_id, result), - ) - } else { - sails_rs::alloy_sol_types::SolValue::abi_encode_sequence(&(result,)) - }; - return Some((output, value, __encode_reply)); + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let (__encode_reply,): (bool,) = sails_rs::alloy_sol_types::SolValue::abi_decode_params( + input, + false, + ) + .ok()?; + let result = self.do_this(); + let value = 0u128; + let output = if __encode_reply { + let message_id = sails_rs::alloy_primitives::B256::new( + sails_rs::gstd::Syscall::message_id().into_bytes(), + ); + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(message_id, result), + ) + } else { + sails_rs::alloy_sol_types::SolValue::abi_encode_sequence( + &(result,), + ) + }; + return Some((output, value, __encode_reply)); + } + _ => None, + } + } else { + None } - None } pub async fn try_handle_solidity_async( mut self, - method: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(sails_rs::Vec, u128, bool)> { use sails_rs::gstd::services::{Service, Exposure}; - None + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: MyEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -133,61 +194,51 @@ where T: Clone, { type Exposure = MyGenericEventsServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for MyGenericEventsService<'_, '_, T> -where - T: Clone, -{ - type CommandsMeta = my_generic_events_service_meta::CommandsMeta; - type QueriesMeta = my_generic_events_service_meta::QueriesMeta; - type EventsMeta = my_generic_events_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod my_generic_events_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::MyGenericEventsService<'_, '_, T> + where + T: Clone, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update(&::HASH); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = MyEvents; @@ -198,7 +249,8 @@ where { const METHODS: &'static [sails_rs::solidity::MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + ::INTERFACE_ID, + 0u16, "DoThis", <<( bool, diff --git a/rs/idl-gen/src/builder.rs b/rs/idl-gen/src/builder.rs index 593bdb53..fa237da9 100644 --- a/rs/idl-gen/src/builder.rs +++ b/rs/idl-gen/src/builder.rs @@ -281,16 +281,16 @@ impl<'a> ServiceBuilder<'a> { .resolve(params_type_id) .ok_or(Error::TypeIdIsUnknown(params_type_id))?; let output_type_id = c.fields[1].ty.id; - let mut output = resolver + let output = resolver .get(output_type_id) .cloned() .ok_or(Error::TypeIdIsUnknown(output_type_id))?; - let mut throws = None; + let throws = None; // TODO: unwrap result param - if let Some((ok, err)) = TypeDecl::result_type_decl(&output) { - output = ok; - throws = Some(err); - }; + // if let Some((ok, err)) = TypeDecl::result_type_decl(&output) { + // output = ok; + // throws = Some(err); + // }; if let scale_info::TypeDef::Composite(params_type) = ¶ms_type.type_def { let params = params_type .fields @@ -347,16 +347,16 @@ impl<'a> ServiceBuilder<'a> { .resolve(params_type_id) .ok_or(Error::TypeIdIsUnknown(params_type_id))?; let output_type_id = c.fields[1].ty.id; - let mut output = resolver + let output = resolver .get(output_type_id) .cloned() .ok_or(Error::TypeIdIsUnknown(output_type_id))?; - let mut throws = None; + let throws = None; // TODO: unwrap result param - if let Some((ok, err)) = TypeDecl::result_type_decl(&output) { - output = ok; - throws = Some(err); - }; + // if let Some((ok, err)) = TypeDecl::result_type_decl(&output) { + // output = ok; + // throws = Some(err); + // }; if let scale_info::TypeDef::Composite(params_type) = ¶ms_type.type_def { let params = params_type .fields @@ -632,7 +632,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, sails_idl_meta::AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(1); } @@ -705,7 +705,7 @@ mod tests { // type CommandsMeta = utils::NoCommands; // type QueriesMeta = utils::NoQueries; // type EventsMeta = utils::NoEvents; - // const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + // const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; // const ASYNC: bool = false; // const INTERFACE_ID: InterfaceId = InterfaceId::zero(); // } @@ -780,23 +780,23 @@ mod tests { #[test] fn base_service_entities_doesnt_automatically_occur() { - struct BaseServiceMeta; - impl ServiceMeta for BaseServiceMeta { + struct BaseService; + impl ServiceMeta for BaseService { type CommandsMeta = BaseServiceCommands; type QueriesMeta = BaseServiceQueries; type EventsMeta = BaseServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(1u64); } - struct ExtendedServiceMeta; - impl ServiceMeta for ExtendedServiceMeta { + struct ExtendedService; + impl ServiceMeta for ExtendedService { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = ExtendedServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseServiceMeta", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(2u64); } @@ -839,21 +839,21 @@ mod tests { #[allow(unused)] struct SomeExtendedServiceType(CodeId); - let services = test_service_units::("ExtendedService") - .expect("ServiceBuilder error"); + let services = + test_service_units::("ExtendedService").expect("ServiceBuilder error"); assert_eq!(services.len(), 2); let base_service = &services[0]; let extended_service = &services[1]; - assert_eq!(base_service.name.name, "BaseServiceMeta"); + assert_eq!(base_service.name.name, "BaseService"); assert_eq!(extended_service.name.name, "ExtendedService"); assert_eq!( extended_service.extends, vec![ServiceIdent { - name: "BaseServiceMeta".to_string(), - interface_id: Some(BaseServiceMeta::INTERFACE_ID) + name: "BaseService".to_string(), + interface_id: Some(BaseService::INTERFACE_ID) }] ); @@ -898,23 +898,23 @@ mod tests { #[test] fn service_extension_with_conflicting_names() { - struct BaseServiceMeta; - impl ServiceMeta for BaseServiceMeta { + struct BaseService; + impl ServiceMeta for BaseService { type CommandsMeta = BaseServiceCommands; type QueriesMeta = BaseServiceQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(10u64); } - struct ExtendedServiceMeta; - impl ServiceMeta for ExtendedServiceMeta { + struct ExtendedService; + impl ServiceMeta for ExtendedService { type CommandsMeta = ExtendedServiceCommands; type QueriesMeta = ExtendedServiceQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(11u64); } @@ -943,8 +943,8 @@ mod tests { ConflictingQuery(utils::SimpleFunctionParams, String), } - let services = test_service_units::("ExtendedService") - .expect("ServiceBuilder error"); + let services = + test_service_units::("ExtendedService").expect("ServiceBuilder error"); assert_eq!(services.len(), 2); let base_service = &services[0]; @@ -995,7 +995,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = BaseServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(20u64); } @@ -1005,8 +1005,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = ExtendedServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(21u64); } @@ -1064,7 +1064,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = BaseServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(30u64); } @@ -1080,8 +1080,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = ExtendedServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("ServiceBase", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("ServiceBase")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(31u64); } @@ -1130,7 +1130,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(40u64); } @@ -1140,7 +1140,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(41u64); } @@ -1150,9 +1150,9 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[ - ("ServiceA1", AnyServiceMeta::new::), - ("ServiceA2", AnyServiceMeta::new::), + const BASE_SERVICES: &'static [BaseServiceMeta] = &[ + BaseServiceMeta::new::("ServiceA1"), + BaseServiceMeta::new::("ServiceA2"), ]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(42u64); @@ -1163,7 +1163,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(43u64); } @@ -1173,9 +1173,9 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[ - ("ServiceB1", AnyServiceMeta::new::), - ("ServiceB2", AnyServiceMeta::new::), + const BASE_SERVICES: &'static [BaseServiceMeta] = &[ + BaseServiceMeta::new::("ServiceB1"), + BaseServiceMeta::new::("ServiceB2"), ]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(44u64); @@ -1204,7 +1204,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(50u64); } @@ -1214,8 +1214,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(51u64); } @@ -1225,8 +1225,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(52u64); } @@ -1252,7 +1252,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(60u64); } @@ -1262,8 +1262,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("BaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("BaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(61u64); } @@ -1273,8 +1273,8 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("RenamedBaseService", AnyServiceMeta::new::)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = + &[BaseServiceMeta::new::("RenamedBaseService")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(62u64); } @@ -1293,37 +1293,37 @@ mod tests { assert_eq!(doc.services.len(), 3); } - #[test] - fn base_services_cycle_detection() { - struct ServiceA; - impl ServiceMeta for ServiceA { - type CommandsMeta = utils::NoCommands; - type QueriesMeta = utils::NoQueries; - type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("ServiceB", AnyServiceMeta::new::)]; - const ASYNC: bool = false; - const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(70u64); - } + // #[test] + // fn base_services_cycle_detection() { + // struct ServiceA; + // impl ServiceMeta for ServiceA { + // type CommandsMeta = utils::NoCommands; + // type QueriesMeta = utils::NoQueries; + // type EventsMeta = utils::NoEvents; + // const BASE_SERVICES: &'static [BaseServiceMeta] = + // &[BaseServiceMeta::new::("ServiceB")]; + // const ASYNC: bool = false; + // const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(70u64); + // } - struct ServiceB; - impl ServiceMeta for ServiceB { - type CommandsMeta = utils::NoCommands; - type QueriesMeta = utils::NoQueries; - type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = - &[("ServiceA", AnyServiceMeta::new::)]; - const ASYNC: bool = false; - const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(71u64); - } + // struct ServiceB; + // impl ServiceMeta for ServiceB { + // type CommandsMeta = utils::NoCommands; + // type QueriesMeta = utils::NoQueries; + // type EventsMeta = utils::NoEvents; + // const BASE_SERVICES: &'static [BaseServiceMeta] = + // &[BaseServiceMeta::new::("ServiceA")]; + // const ASYNC: bool = false; + // const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(71u64); + // } - let res = test_service_units::("ServiceA"); - assert!(res.is_err()); - let Err(Error::MetaIsInvalid(msg)) = res else { - panic!("Expected MetaIsInvalid error, got {res:?}"); - }; - assert!(msg.contains("cyclic base services")); - } + // let res = test_service_units::("ServiceA"); + // assert!(res.is_err()); + // let Err(Error::MetaIsInvalid(msg)) = res else { + // panic!("Expected MetaIsInvalid error, got {res:?}"); + // }; + // assert!(msg.contains("cyclic base services")); + // } // #[test] // #[ignore = "TODO [future]: Must be error when Sails binary protocol is implemented"] @@ -1333,7 +1333,7 @@ mod tests { // type CommandsMeta = utils::NoCommands; // type QueriesMeta = utils::NoQueries; // type EventsMeta = utils::NoEvents; - // const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + // const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; // const ASYNC: bool = false; // const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(70u64); // } @@ -1343,7 +1343,7 @@ mod tests { // type CommandsMeta = utils::NoCommands; // type QueriesMeta = utils::NoQueries; // type EventsMeta = utils::NoEvents; - // const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[ + // const BASE_SERVICES: &'static [BaseServiceMeta] = &[ // ("ServiceA", AnyServiceMeta::new::), // ("ServiceA", AnyServiceMeta::new::), // ]; @@ -1358,7 +1358,7 @@ mod tests { // type CommandsMeta = utils::NoCommands; // type QueriesMeta = utils::NoQueries; // type EventsMeta = utils::NoEvents; - // const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[ + // const BASE_SERVICES: &'static [BaseServiceMeta] = &[ // ("ServiceA", AnyServiceMeta::new::), // ("RenamedServiceA", AnyServiceMeta::new::), // ]; @@ -1380,7 +1380,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = InvalidEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(80u64); } @@ -1409,7 +1409,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = EventServiceEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(81u64); } @@ -1514,7 +1514,7 @@ mod tests { type CommandsMeta = NotVariantCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(90u64); } @@ -1524,7 +1524,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = NotVariantQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(91u64); } @@ -1563,7 +1563,7 @@ mod tests { type CommandsMeta = BadCommands1; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(100u64); } @@ -1573,7 +1573,7 @@ mod tests { type CommandsMeta = BadCommands2; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(101u64); } @@ -1583,7 +1583,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = BadQueries1; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(102u64); } @@ -1593,7 +1593,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = BadQueries2; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(103u64); } @@ -1657,7 +1657,7 @@ mod tests { type CommandsMeta = BadCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(110u64); } @@ -1689,7 +1689,7 @@ mod tests { type CommandsMeta = BadCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(111u64); } @@ -1714,109 +1714,110 @@ mod tests { assert_eq!(msg.as_str(), "command `BadCmd` param is missing a name"); } - #[test] - fn service_fns_result_ty() { - struct TestServiceMeta; - impl ServiceMeta for TestServiceMeta { - type CommandsMeta = TestCommands; - type QueriesMeta = TestQueries; - type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(120u64); - } + // TODO: Result unwrapping + // #[test] + // fn service_fns_result_ty() { + // struct TestServiceMeta; + // impl ServiceMeta for TestServiceMeta { + // type CommandsMeta = TestCommands; + // type QueriesMeta = TestQueries; + // type EventsMeta = utils::NoEvents; + // const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; + // const ASYNC: bool = false; + // const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(120u64); + // } - #[derive(TypeInfo)] - #[allow(unused)] - enum TestCommands { - Unit(utils::SimpleFunctionParams, ()), - NonUnit(utils::SimpleFunctionParams, String), - WithUnit(utils::SimpleFunctionParams, Result<(), u32>), - Result(utils::SimpleFunctionParams, Result), - } + // #[derive(TypeInfo)] + // #[allow(unused)] + // enum TestCommands { + // Unit(utils::SimpleFunctionParams, ()), + // NonUnit(utils::SimpleFunctionParams, String), + // WithUnit(utils::SimpleFunctionParams, Result<(), u32>), + // Result(utils::SimpleFunctionParams, Result), + // } - #[derive(TypeInfo)] - #[allow(unused)] - enum TestQueries { - Unit(utils::SimpleFunctionParams, ()), - NonUnit(utils::SimpleFunctionParams, u32), - WithUnit(utils::SimpleFunctionParams, Result<(), u32>), - Result(utils::SimpleFunctionParams, Result), - } + // #[derive(TypeInfo)] + // #[allow(unused)] + // enum TestQueries { + // Unit(utils::SimpleFunctionParams, ()), + // NonUnit(utils::SimpleFunctionParams, u32), + // WithUnit(utils::SimpleFunctionParams, Result<(), u32>), + // Result(utils::SimpleFunctionParams, Result), + // } - let services = - test_service_units::("TestService").expect("ServiceBuilder error"); - assert_eq!(services.len(), 1); - let service = &services[0]; + // let services = + // test_service_units::("TestService").expect("ServiceBuilder error"); + // assert_eq!(services.len(), 1); + // let service = &services[0]; - let get = |name: &str, kind: FunctionKind| -> &ServiceFunc { - service - .funcs - .iter() - .find(|f| f.name == name && f.kind == kind) - .unwrap_or_else(|| panic!("missing {kind:?} {name}")) - }; + // let get = |name: &str, kind: FunctionKind| -> &ServiceFunc { + // service + // .funcs + // .iter() + // .find(|f| f.name == name && f.kind == kind) + // .unwrap_or_else(|| panic!("missing {kind:?} {name}")) + // }; - assert_eq!( - get("Unit", FunctionKind::Command).output, - TypeDecl::Primitive(PrimitiveType::Void) - ); - assert_eq!(get("Unit", FunctionKind::Command).throws, None); + // assert_eq!( + // get("Unit", FunctionKind::Command).output, + // TypeDecl::Primitive(PrimitiveType::Void) + // ); + // assert_eq!(get("Unit", FunctionKind::Command).throws, None); - assert_eq!( - get("NonUnit", FunctionKind::Command).output, - TypeDecl::Primitive(PrimitiveType::String) - ); - assert_eq!(get("NonUnit", FunctionKind::Command).throws, None); + // assert_eq!( + // get("NonUnit", FunctionKind::Command).output, + // TypeDecl::Primitive(PrimitiveType::String) + // ); + // assert_eq!(get("NonUnit", FunctionKind::Command).throws, None); - assert_eq!( - get("WithUnit", FunctionKind::Command).output, - TypeDecl::Primitive(PrimitiveType::Void) - ); - assert_eq!( - get("WithUnit", FunctionKind::Command).throws, - Some(TypeDecl::Primitive(PrimitiveType::U32)) - ); + // assert_eq!( + // get("WithUnit", FunctionKind::Command).output, + // TypeDecl::Primitive(PrimitiveType::Void) + // ); + // assert_eq!( + // get("WithUnit", FunctionKind::Command).throws, + // Some(TypeDecl::Primitive(PrimitiveType::U32)) + // ); - assert_eq!( - get("Result", FunctionKind::Command).output, - TypeDecl::Primitive(PrimitiveType::U32) - ); - assert_eq!( - get("Result", FunctionKind::Command).throws, - Some(TypeDecl::Primitive(PrimitiveType::String)) - ); + // assert_eq!( + // get("Result", FunctionKind::Command).output, + // TypeDecl::Primitive(PrimitiveType::U32) + // ); + // assert_eq!( + // get("Result", FunctionKind::Command).throws, + // Some(TypeDecl::Primitive(PrimitiveType::String)) + // ); - assert_eq!( - get("Unit", FunctionKind::Query).output, - TypeDecl::Primitive(PrimitiveType::Void) - ); - assert_eq!(get("Unit", FunctionKind::Query).throws, None); + // assert_eq!( + // get("Unit", FunctionKind::Query).output, + // TypeDecl::Primitive(PrimitiveType::Void) + // ); + // assert_eq!(get("Unit", FunctionKind::Query).throws, None); - assert_eq!( - get("NonUnit", FunctionKind::Query).output, - TypeDecl::Primitive(PrimitiveType::U32) - ); - assert_eq!(get("NonUnit", FunctionKind::Query).throws, None); + // assert_eq!( + // get("NonUnit", FunctionKind::Query).output, + // TypeDecl::Primitive(PrimitiveType::U32) + // ); + // assert_eq!(get("NonUnit", FunctionKind::Query).throws, None); - assert_eq!( - get("WithUnit", FunctionKind::Query).output, - TypeDecl::Primitive(PrimitiveType::Void) - ); - assert_eq!( - get("WithUnit", FunctionKind::Query).throws, - Some(TypeDecl::Primitive(PrimitiveType::U32)) - ); + // assert_eq!( + // get("WithUnit", FunctionKind::Query).output, + // TypeDecl::Primitive(PrimitiveType::Void) + // ); + // assert_eq!( + // get("WithUnit", FunctionKind::Query).throws, + // Some(TypeDecl::Primitive(PrimitiveType::U32)) + // ); - assert_eq!( - get("Result", FunctionKind::Query).output, - TypeDecl::Primitive(PrimitiveType::U32) - ); - assert_eq!( - get("Result", FunctionKind::Query).throws, - Some(TypeDecl::Primitive(PrimitiveType::String)) - ); - } + // assert_eq!( + // get("Result", FunctionKind::Query).output, + // TypeDecl::Primitive(PrimitiveType::U32) + // ); + // assert_eq!( + // get("Result", FunctionKind::Query).throws, + // Some(TypeDecl::Primitive(PrimitiveType::String)) + // ); + // } #[test] fn service_function_variations_positive_test() { @@ -1825,7 +1826,7 @@ mod tests { type CommandsMeta = OneFunction; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(130u64); } @@ -1835,7 +1836,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = OneFunction; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(131u64); } @@ -1845,7 +1846,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(132u64); } @@ -1903,7 +1904,7 @@ mod tests { type CommandsMeta = ServiceCommands; type QueriesMeta = ServiceQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(133u64); } @@ -1986,7 +1987,7 @@ mod tests { type CommandsMeta = CommandsWithNonUserDefinedArgs; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(140u64); } @@ -1996,7 +1997,7 @@ mod tests { type CommandsMeta = CommandWithUserDefinedArgs; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(141u64); } @@ -2006,7 +2007,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = CommandsWithNonUserDefinedArgs; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(142u64); } @@ -2016,7 +2017,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = CommandWithUserDefinedArgs; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(143u64); } @@ -2026,7 +2027,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = EventsWithNonUserDefinedArgs; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(144u64); } @@ -2036,7 +2037,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = EventsWithUserDefinedArgs; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(145u64); } @@ -2206,7 +2207,7 @@ mod tests { type CommandsMeta = Service1Commands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(150u64); } @@ -2216,7 +2217,7 @@ mod tests { type CommandsMeta = Service2Commands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(151u64); } @@ -2306,7 +2307,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(160u64); } @@ -2316,7 +2317,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(161u64); } @@ -2326,7 +2327,7 @@ mod tests { type CommandsMeta = utils::NoCommands; type QueriesMeta = utils::NoQueries; type EventsMeta = utils::NoEvents; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(162u64); } diff --git a/rs/idl-gen/tests/generator.rs b/rs/idl-gen/tests/generator.rs index ae0a042d..21cc02c0 100644 --- a/rs/idl-gen/tests/generator.rs +++ b/rs/idl-gen/tests/generator.rs @@ -1,7 +1,9 @@ use gprimitives::*; use meta_params::*; use sails_idl_gen::{program, service}; -use sails_idl_meta::{AnyServiceMeta, AnyServiceMetaFn, InterfaceId, ProgramMeta, ServiceMeta}; +use sails_idl_meta::{ + AnyServiceMeta, AnyServiceMetaFn, BaseServiceMeta, InterfaceId, ProgramMeta, ServiceMeta, +}; use scale_info::{StaticTypeInfo, TypeInfo}; use std::{collections::BTreeMap, result::Result as StdResult}; @@ -188,7 +190,7 @@ impl Ser type CommandsMeta = C; type QueriesMeta = Q; type EventsMeta = E; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)] = &[]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(ID); } @@ -206,13 +208,12 @@ impl)]; + const BASE_SERVICES: &'static [BaseServiceMeta] = &[BaseServiceMeta::new::("B")]; const ASYNC: bool = false; const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(ID); } -type TestServiceMeta = GenericService; +type TestServiceMeta = GenericService; #[allow(dead_code)] #[derive(TypeInfo)] @@ -347,7 +348,7 @@ fn service_idl_works_with_base_services() { QueriesMeta, EventsMeta, GenericService, - 0xc4aaf5c4932ab704, + 0x10a0a7803b912783, >, >("ServiceMetaWithBase", &mut idl) .unwrap(); diff --git a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_empty_ctors.snap b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_empty_ctors.snap index da846e21..c907327f 100644 --- a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_empty_ctors.snap +++ b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_empty_ctors.snap @@ -4,7 +4,7 @@ expression: idl --- !@sails: 0.9.2 -service Service@0xd6ed5296008aed60 { +service Service@0xd42ae9a4dc1efdf0 { events { /// `That` Done too ThatDone { @@ -27,7 +27,7 @@ service Service@0xd6ed5296008aed60 { /// Some multiline description /// Second line /// Third line - DoThat(par1: DoThatParam) -> (String, u32) throws (String); + DoThat(par1: DoThatParam) -> Result<(String, u32), (String)>; /// Some description DoThis(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericStruct, p6: GenericStruct, p7: GenericConstStructN8, p8: GenericConstStructN32) -> String; /// This is a second query @@ -36,7 +36,7 @@ service Service@0xd6ed5296008aed60 { That(pr1: ThatParam) -> String; /// This is a query @query - This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> (String, u32) throws String; + This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> Result<(String, u32), String>; } types { struct DoThatParam { @@ -90,6 +90,6 @@ service Service@0xd6ed5296008aed60 { program TestProgramWithEmptyCtorsMeta { services { - Service@0xd6ed5296008aed60, + Service@0xd42ae9a4dc1efdf0, } } diff --git a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_multiple_services.snap b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_multiple_services.snap index b6db8c35..ad2ae962 100644 --- a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_multiple_services.snap +++ b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_multiple_services.snap @@ -4,7 +4,7 @@ expression: idl --- !@sails: 0.9.2 -service Service@0xd6ed5296008aed60 { +service Service@0xd42ae9a4dc1efdf0 { events { /// `That` Done too ThatDone { @@ -27,7 +27,7 @@ service Service@0xd6ed5296008aed60 { /// Some multiline description /// Second line /// Third line - DoThat(par1: DoThatParam) -> (String, u32) throws (String); + DoThat(par1: DoThatParam) -> Result<(String, u32), (String)>; /// Some description DoThis(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericStruct, p6: GenericStruct, p7: GenericConstStructN8, p8: GenericConstStructN32) -> String; /// This is a second query @@ -36,7 +36,7 @@ service Service@0xd6ed5296008aed60 { That(pr1: ThatParam) -> String; /// This is a query @query - This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> (String, u32) throws String; + This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> Result<(String, u32), String>; } types { struct DoThatParam { @@ -90,7 +90,7 @@ service Service@0xd6ed5296008aed60 { program TestProgramWithMultipleServicesMeta { services { - Service@0xd6ed5296008aed60, - Service@0xd6ed5296008aed60: SomeService, + Service@0xd42ae9a4dc1efdf0, + Service@0xd42ae9a4dc1efdf0: SomeService, } } diff --git a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_non_empty_ctors.snap b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_non_empty_ctors.snap index 73f43f34..b4fbe18e 100644 --- a/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_non_empty_ctors.snap +++ b/rs/idl-gen/tests/snapshots/generator__program_idl_works_with_non_empty_ctors.snap @@ -4,7 +4,7 @@ expression: idl --- !@sails: 0.9.2 -service Test@0xd6ed5296008aed60 { +service Test@0xd42ae9a4dc1efdf0 { events { /// `That` Done too ThatDone { @@ -27,7 +27,7 @@ service Test@0xd6ed5296008aed60 { /// Some multiline description /// Second line /// Third line - DoThat(par1: DoThatParam) -> (String, u32) throws (String); + DoThat(par1: DoThatParam) -> Result<(String, u32), (String)>; /// Some description DoThis(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericStruct, p6: GenericStruct, p7: GenericConstStructN8, p8: GenericConstStructN32) -> String; /// This is a second query @@ -36,7 +36,7 @@ service Test@0xd6ed5296008aed60 { That(pr1: ThatParam) -> String; /// This is a query @query - This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> (String, u32) throws String; + This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> Result<(String, u32), String>; } types { struct DoThatParam { @@ -97,6 +97,6 @@ program TestProgramWithNonEmptyCtorsMeta { FromStr(p1: String); } services { - Test@0xd6ed5296008aed60, + Test@0xd42ae9a4dc1efdf0, } } diff --git a/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_base_services.snap b/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_base_services.snap index 048151a0..af92a162 100644 --- a/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_base_services.snap +++ b/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_base_services.snap @@ -21,7 +21,7 @@ service B@0x256fb43427bef08e { } } -service ServiceMetaWithBase@0xc4aaf5c4932ab704 { +service ServiceMetaWithBase@0x10a0a7803b912783 { extends { B@0x256fb43427bef08e, } @@ -47,7 +47,7 @@ service ServiceMetaWithBase@0xc4aaf5c4932ab704 { /// Some multiline description /// Second line /// Third line - DoThat(par1: DoThatParam) -> (String, u32) throws (String); + DoThat(par1: DoThatParam) -> Result<(String, u32), (String)>; /// Some description DoThis(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericStruct, p6: GenericStruct, p7: GenericConstStructN8, p8: GenericConstStructN32) -> String; /// This is a second query @@ -56,7 +56,7 @@ service ServiceMetaWithBase@0xc4aaf5c4932ab704 { That(pr1: ThatParam) -> String; /// This is a query @query - This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> (String, u32) throws String; + This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> Result<(String, u32), String>; } types { struct DoThatParam { diff --git a/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_basics.snap b/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_basics.snap index 6f2a30b0..6c7cf179 100644 --- a/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_basics.snap +++ b/rs/idl-gen/tests/snapshots/generator__service_idl_works_with_basics.snap @@ -4,7 +4,7 @@ expression: idl --- !@sails: 0.9.2 -service TestServiceMeta@0xd6ed5296008aed60 { +service TestServiceMeta@0xd42ae9a4dc1efdf0 { events { /// `That` Done too ThatDone { @@ -27,7 +27,7 @@ service TestServiceMeta@0xd6ed5296008aed60 { /// Some multiline description /// Second line /// Third line - DoThat(par1: DoThatParam) -> (String, u32) throws (String); + DoThat(par1: DoThatParam) -> Result<(String, u32), (String)>; /// Some description DoThis(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericStruct, p6: GenericStruct, p7: GenericConstStructN8, p8: GenericConstStructN32) -> String; /// This is a second query @@ -36,7 +36,7 @@ service TestServiceMeta@0xd6ed5296008aed60 { That(pr1: ThatParam) -> String; /// This is a query @query - This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> (String, u32) throws String; + This(p1: u32, p2: String, p3: (Option, u8), p4: TupleStruct, p5: GenericEnum) -> Result<(String, u32), String>; } types { struct DoThatParam { diff --git a/rs/src/header.rs b/rs/idl-meta/src/header.rs similarity index 95% rename from rs/src/header.rs rename to rs/idl-meta/src/header.rs index ff777dc5..0e2b7f08 100644 --- a/rs/src/header.rs +++ b/rs/idl-meta/src/header.rs @@ -1,8 +1,5 @@ -use crate::{ - Vec, - meta::InterfaceId, - scale_codec::{Decode, Encode, Error, Input, Output}, -}; +use crate::{InterfaceId, Vec}; +use parity_scale_codec::{Decode, Encode, Error, Input, Output}; /// Sails protocol highest supported version. pub const HIGHEST_SUPPORTED_VERSION: u8 = 1; @@ -29,7 +26,7 @@ pub struct SailsMessageHeader { impl SailsMessageHeader { /// Creates a new Sails message header. - pub fn new( + pub const fn new( version: Version, hlen: HeaderLength, interface_id: InterfaceId, @@ -45,28 +42,38 @@ impl SailsMessageHeader { } } + pub const fn v1(interface_id: InterfaceId, entry_id: u16, route_id: u8) -> Self { + Self { + version: Version::v1(), + hlen: HeaderLength(MINIMAL_HLEN), + interface_id, + route_id, + entry_id, + } + } + /// Gets the version of the header. - pub fn version(&self) -> Version { + pub const fn version(&self) -> Version { self.version } /// Gets the header length. - pub fn hlen(&self) -> HeaderLength { + pub const fn hlen(&self) -> HeaderLength { self.hlen } /// Gets the interface ID. - pub fn interface_id(&self) -> InterfaceId { + pub const fn interface_id(&self) -> InterfaceId { self.interface_id } /// Gets the route ID. - pub fn route_id(&self) -> u8 { + pub const fn route_id(&self) -> u8 { self.route_id } /// Gets the entry ID. - pub fn entry_id(&self) -> u16 { + pub const fn entry_id(&self) -> u16 { self.entry_id } } @@ -143,7 +150,15 @@ impl SailsMessageHeader { .iter() .filter_map(|(id, r_id)| (*id == interface_id).then_some(*r_id)) .fold((0, false), |(count, found), program_route_id| { - (count + 1, found || message_route_id == program_route_id) + let new_count = count + 1; + + let new_found = if !found { + message_route_id == program_route_id + } else { + found + }; + + (new_count, new_found) }); if same_interface_ids == 0 { @@ -240,12 +255,12 @@ pub struct Version(u8); impl Version { /// Instantiates the type with version 1. - pub fn v1() -> Self { + pub const fn v1() -> Self { Self(1) } /// Instantiates the type with the latest supported version. - pub fn latest() -> Self { + pub const fn latest() -> Self { Self(HIGHEST_SUPPORTED_VERSION) } @@ -544,7 +559,7 @@ mod tests { } #[test] - fn message_header_try_read_fails_insufficient_bytes() { + fn message_header_try_read_fails_invalid_magic() { // Insufficient bytes (no route id) let bytes = [0x47, 0x4D, 1, 15, 1, 2, 3, 4, 5, 6, 7, 8, 210, 4]; diff --git a/rs/idl-meta/src/lib.rs b/rs/idl-meta/src/lib.rs index 01c2aa2a..5fab5bd1 100644 --- a/rs/idl-meta/src/lib.rs +++ b/rs/idl-meta/src/lib.rs @@ -16,6 +16,9 @@ pub use ast::*; use parity_scale_codec::{Decode, Encode, Error}; use scale_info::{MetaType, StaticTypeInfo, prelude::vec::Vec}; +mod header; +pub use header::*; + pub type AnyServiceMetaFn = fn() -> AnyServiceMeta; /// Unique identifier for a service (or "interface" in terms of sails binary protocol). @@ -80,7 +83,7 @@ impl InterfaceId { impl core::fmt::Debug for InterfaceId { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", &self) + core::fmt::Display::fmt(self, f) } } @@ -134,11 +137,33 @@ impl Decode for InterfaceId { } } +#[derive(Debug, Clone)] +pub struct BaseServiceMeta { + pub name: &'static str, + pub interface_id: InterfaceId, + pub meta: AnyServiceMetaFn, + pub base: &'static [BaseServiceMeta], +} + +impl BaseServiceMeta { + pub const fn new(name: &'static str) -> Self { + Self { + name, + interface_id: S::INTERFACE_ID, + meta: AnyServiceMeta::new::, + base: S::BASE_SERVICES, + } + } +} + pub trait ServiceMeta { type CommandsMeta: StaticTypeInfo; type QueriesMeta: StaticTypeInfo; type EventsMeta: StaticTypeInfo; - const BASE_SERVICES: &'static [(&'static str, AnyServiceMetaFn)]; + /// The order of base services here is lexicographical by their names + const BASE_SERVICES: &'static [BaseServiceMeta]; + /// The order of base services here is lexicographical by their names + // const BASE_SERVICES_IDS: &'static [AnyServiceIds]; const ASYNC: bool; const INTERFACE_ID: InterfaceId; @@ -154,8 +179,8 @@ pub trait ServiceMeta { MetaType::new::() } - fn base_services() -> impl Iterator { - Self::BASE_SERVICES.iter().map(|&(name, f)| (name, f())) + fn base_services() -> &'static [BaseServiceMeta] { + Self::BASE_SERVICES } } @@ -163,7 +188,7 @@ pub struct AnyServiceMeta { commands: MetaType, queries: MetaType, events: MetaType, - base_services: Vec<(&'static str, AnyServiceMetaFn)>, + base_services: Vec, interface_id: InterfaceId, } @@ -191,7 +216,9 @@ impl AnyServiceMeta { } pub fn base_services(&self) -> impl Iterator { - self.base_services.iter().map(|&(name, f)| (name, f())) + self.base_services + .iter() + .map(|base| (base.name, (base.meta)())) } pub fn interface_id(&self) -> InterfaceId { @@ -213,6 +240,86 @@ pub trait ProgramMeta { } } +pub const fn count_base_services() -> usize { + let mut counter = 0; + + let direct_base_services = S::BASE_SERVICES; + let mut idx = 0; + while idx != direct_base_services.len() { + let base = &direct_base_services[idx]; + count_base_services_recursive(&mut counter, base); + idx += 1; + } + + counter +} + +const fn count_base_services_recursive(counter: &mut usize, base: &BaseServiceMeta) { + *counter += 1; + + let base_services = base.base; + let mut idx = 0; + while idx != base_services.len() { + count_base_services_recursive(counter, &base_services[idx]); + idx += 1; + } +} + +/// Generate interface IDs array from exposed services +pub const fn interface_ids( + exposed_services: &'static [BaseServiceMeta], +) -> [(InterfaceId, u8); N] { + let mut output = [(InterfaceId([0u8; 8]), 0u8); N]; + + let mut exposed_svc_idx = 0; + let mut output_offset = 0; + let mut route_id = 1; + while exposed_svc_idx != exposed_services.len() { + let service = &exposed_services[exposed_svc_idx]; + fill_interface_ids_recursive(&mut output, &mut output_offset, service, route_id); + exposed_svc_idx += 1; + route_id += 1; + } + + assert!(output_offset == N, "Mismatched interface IDs count"); + + output +} + +const fn fill_interface_ids_recursive( + arr: &mut [(InterfaceId, u8)], + offset: &mut usize, + service: &BaseServiceMeta, + route_id: u8, +) { + arr[*offset] = (service.interface_id, route_id); + *offset += 1; + let base_services = service.base; + let mut idx = 0; + while idx != base_services.len() { + fill_interface_ids_recursive(arr, offset, &base_services[idx], route_id); + idx += 1; + } +} + +pub const fn service_has_interface_id( + service: &BaseServiceMeta, + interface_id: InterfaceId, +) -> bool { + if service.interface_id.as_u64() == interface_id.as_u64() { + true + } else { + let mut idx = 0; + while idx != service.base.len() { + if service_has_interface_id(&service.base[idx], interface_id) { + return true; + } + idx += 1; + } + false + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rs/macros/core/src/event/mod.rs b/rs/macros/core/src/event/mod.rs index 4460b121..9960ed54 100644 --- a/rs/macros/core/src/event/mod.rs +++ b/rs/macros/core/src/event/mod.rs @@ -21,6 +21,11 @@ pub fn event(attrs: TokenStream, input: TokenStream) -> TokenStream { ) }); + // Sort variants alphabetically to ensure deterministic order for hashing and routing + let mut variants: Vec<_> = input.variants.into_iter().collect(); + variants.sort_by_key(|v| v.ident.to_string().to_lowercase()); + input.variants = variants.into_iter().collect(); + // Parse the attributes into a syntax tree. let sails_path_attr = syn::parse2::(attrs).ok(); let sails_path = &sails_path_or_default(sails_path_attr.map(|attr| attr.path())); @@ -58,8 +63,9 @@ fn generate_sails_event_impl(input: &ItemEnum, sails_path: &Path) -> TokenStream // Build match arms for each variant let mut match_arms = Vec::new(); + let mut entry_id_arms = Vec::new(); - for variant in variants { + for (idx, variant) in variants.iter().enumerate() { let variant_ident = &variant.ident; // Determine the pattern to match this variant, ignoring its fields: let pattern = match &variant.fields { @@ -84,6 +90,11 @@ fn generate_sails_event_impl(input: &ItemEnum, sails_path: &Path) -> TokenStream #pattern => &[ #( #encoded_name ),* ] }; match_arms.push(arm); + + let idx = idx as u16; + entry_id_arms.push(quote! { + #pattern => #idx + }); } // Generate the impl block for `Event` @@ -95,6 +106,12 @@ fn generate_sails_event_impl(input: &ItemEnum, sails_path: &Path) -> TokenStream } } + fn entry_id(&self) -> u16 { + match self { + #( #entry_id_arms ),* + } + } + fn skip_bytes() -> usize { 1 // The first byte is reserved for the index of the event enum variant } diff --git a/rs/macros/core/src/program/ethexe.rs b/rs/macros/core/src/program/ethexe.rs index e05bd32b..e8d1b803 100644 --- a/rs/macros/core/src/program/ethexe.rs +++ b/rs/macros/core/src/program/ethexe.rs @@ -6,7 +6,7 @@ impl ProgramBuilder { /// Generates code /// ```rust /// impl sails_rs::solidity::ProgramSignature for MyProgram { - /// const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[( + /// const CTORS: &'static [sails_rs::solidity::MethodExpo] = &[( /// &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8] as &[u8], /// "create", /// <<(bool) as sails_rs::alloy_sol_types::SolValue>::SolType as sails_rs::alloy_sol_types::SolType>::SOL_NAME, @@ -31,7 +31,7 @@ impl ProgramBuilder { let program_ctors = self.program_ctors(); let program_ctor_sigs = program_ctors .iter() - .map(|fn_builder| fn_builder.sol_handler_signature(false)); + .map(|fn_builder| fn_builder.sol_handler_signature(None)); let service_ctors = self.service_ctors(); let service_ctor_sigs = service_ctors @@ -72,7 +72,7 @@ impl ProgramBuilder { = #sails_path::solidity::ConstProgramMeta::<#program_type_path>::ctor_callback_sigs(); const __METHOD_SIGS: [[u8; 4]; <#program_type_path as #sails_path::solidity::ProgramSignature>::METHODS_LEN] = #sails_path::solidity::ConstProgramMeta::<#program_type_path>::method_sigs(); - const __METHOD_ROUTES: [(&'static [u8], &'static [u8]); <#program_type_path as #sails_path::solidity::ProgramSignature>::METHODS_LEN] + const __METHOD_ROUTES: [(#sails_path::meta::InterfaceId, u16, u8); <#program_type_path as #sails_path::solidity::ProgramSignature>::METHODS_LEN] = #sails_path::solidity::ConstProgramMeta::<#program_type_path>::method_routes(); const __CALLBACK_SIGS: [[u8; 4]; <#program_type_path as #sails_path::solidity::ProgramSignature>::METHODS_LEN] = #sails_path::solidity::ConstProgramMeta::<#program_type_path>::callback_sigs(); @@ -87,9 +87,11 @@ impl ProgramBuilder { .map(|fn_builder| fn_builder.sol_ctor_branch_impl(program_type_path, program_ident)); quote! { - fn match_ctor_solidity(ctor: &[u8], input: &[u8]) -> Option { - #( #ctor_branches )* - None + fn match_ctor_solidity(entry_id: u16, input: &[u8]) -> Option { + match entry_id { + #( #ctor_branches )* + _ => None, + } } } } @@ -101,8 +103,8 @@ impl ProgramBuilder { quote! { if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&#input_ident[..4]) { if let Some(idx) = __CTOR_SIGS.iter().position(|s| s == &sig) { - let (ctor_route, ..) = <#program_type_path as #sails_path::solidity::ProgramSignature>::CTORS[idx]; - if let Some(encode_reply) = match_ctor_solidity(ctor_route, &#input_ident[4..]) { + let (_, entry_id, ..) = <#program_type_path as #sails_path::solidity::ProgramSignature>::CTORS[idx]; + if let Some(encode_reply) = match_ctor_solidity(entry_id, &#input_ident[4..]) { // add callbak selector if `encode_reply` is set if encode_reply { let output = [__CTOR_CALLBACK_SIGS[idx].as_slice(), gstd::msg::id().into_bytes().as_slice()].concat(); @@ -119,7 +121,7 @@ impl ProgramBuilder { quote! { if let Ok(sig) = TryInto::<[u8; 4]>::try_into(&input[..4]) { if let Some(idx) = __METHOD_SIGS.iter().position(|s| s == &sig) { - let (route, method) = __METHOD_ROUTES[idx]; + let (interface_id, entry_id, route_idx) = __METHOD_ROUTES[idx]; #(#solidity_dispatchers)* } } @@ -130,23 +132,23 @@ impl ProgramBuilder { impl FnBuilder<'_> { fn sol_service_signature(&self) -> TokenStream { let sails_path = self.sails_path; - let service_route_bytes = self.encoded_route.as_slice(); + let route_idx = (self.entry_id + 1) as u8; let service_name = self.route_camel_case(); let service_type = &self.result_type; quote! { ( #service_name, - &[ #(#service_route_bytes),* ] as &[u8], + #route_idx, <#service_type as #sails_path::solidity::ServiceSignature>::METHODS, ) } } - pub(crate) fn sol_handler_signature(&self, is_service: bool) -> TokenStream { + pub(crate) fn sol_handler_signature(&self, service_path: Option<&TypePath>) -> TokenStream { let sails_path = self.sails_path; - let handler_route_bytes = self.encoded_route.as_slice(); - let handler_name = if is_service { + let entry_id = self.entry_id; + let handler_name = if service_path.is_some() { // method name as PascalCase &self.route } else { @@ -155,12 +157,22 @@ impl FnBuilder<'_> { }; let handler_types = self.params_types(); let (result_type, _) = self.result_type_with_value(); + let intrface_id = if let Some(service_path) = service_path { + let path_wo_lifetimes = shared::remove_lifetimes(&service_path.path); + quote! { + <#path_wo_lifetimes as #sails_path::meta::ServiceMeta>::INTERFACE_ID + } + } else { + quote! { + #sails_path::meta::InterfaceId::zero() + } + }; // add `bool` to method signature as first parameter as encode reply let handler_types = quote! { bool, #(#handler_types,)* }; // add MessageId (alloy_primitives::B256) to callback signature as first parameter - let callback_types = if is_service { + let callback_types = if service_path.is_some() { quote! { #sails_path::alloy_primitives::B256, #result_type } } else { quote! { #sails_path::alloy_primitives::B256, } @@ -168,7 +180,8 @@ impl FnBuilder<'_> { quote! { ( - &[ #(#handler_route_bytes),* ] as &[u8], + #intrface_id, + #entry_id, #handler_name, <<(#handler_types) as #sails_path::alloy_sol_types::SolValue>::SolType as #sails_path::alloy_sol_types::SolType>::SOL_NAME, <<(#callback_types) as #sails_path::alloy_sol_types::SolValue>::SolType as #sails_path::alloy_sol_types::SolType>::SOL_NAME, @@ -182,7 +195,7 @@ impl FnBuilder<'_> { program_ident: &Ident, ) -> TokenStream { let sails_path = self.sails_path; - let handler_route_bytes = self.encoded_route.as_slice(); + let entry_id = self.entry_id; let handler_ident = self.ident; let handler_params = self.params_idents(); let handler_types = self.params_types(); @@ -205,28 +218,30 @@ impl FnBuilder<'_> { // read uint128 as first parameter quote! { - if ctor == &[ #(#handler_route_bytes),* ] { + #entry_id => { let (__encode_reply, #(#handler_params,)*) : (bool, #(#handler_types,)*) = #sails_path::alloy_sol_types::SolValue::abi_decode_params(input, false).expect("Failed to decode request"); #ctor_invocation - return Some(__encode_reply); + Some(__encode_reply) } } } pub(crate) fn sol_service_invocation(&self) -> TokenStream2 { - let route_ident = &self.route_ident(); + let sails_path = self.sails_path; + let route_idx = (self.entry_id + 1) as u8; let service_ctor_ident = self.ident; + let service_type = &self.result_type; quote! { - if route == & #route_ident { + if route_idx == #route_idx { let mut service = program_ref.#service_ctor_ident(); - let Some(is_async) = service.check_asyncness(method) else { + let Some(is_async) = <#service_type as #sails_path::gstd::services::Service>::Exposure::check_asyncness(interface_id, entry_id) else { gstd::unknown_input_panic("Unknown service method", &input); }; if is_async { gstd::message_loop(async move { let (output, value, encode_reply) = service - .try_handle_solidity_async(method, &input[4..]) + .try_handle_solidity_async(interface_id, entry_id, &input[4..]) .await .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) @@ -242,7 +257,7 @@ impl FnBuilder<'_> { }); } else { let (output, value, encode_reply) = service - .try_handle_solidity(method, &input[4..]) + .try_handle_solidity(interface_id, entry_id, &input[4..]) .unwrap_or_else(|| { gstd::unknown_input_panic("Unknown request", &input) }); diff --git a/rs/macros/core/src/program/mod.rs b/rs/macros/core/src/program/mod.rs index 56ea5413..3581093e 100644 --- a/rs/macros/core/src/program/mod.rs +++ b/rs/macros/core/src/program/mod.rs @@ -140,10 +140,8 @@ impl ProgramBuilder { &mut self, program_ident: &Ident, ) -> (TokenStream2, TokenStream2, TokenStream2, TokenStream2) { - let mut services_route = Vec::new(); let mut services_meta = Vec::new(); let mut meta_asyncness = Vec::new(); - let mut invocation_dispatches = Vec::new(); let mut routes = BTreeMap::new(); // only used for ethexe #[allow(unused_mut)] @@ -158,66 +156,73 @@ impl ProgramBuilder { meta_asyncness.push(quote!(true)); } - let item_impl = self - .program_impl - .items - .iter() - .enumerate() - .filter_map(|(idx, impl_item)| { - if let ImplItem::Fn(fn_item) = impl_item - && service_ctor_predicate(fn_item) + // Collect all data we need in one pass without holding borrows + let mut modifications = Vec::new(); + let mut services_count_data = Vec::new(); // Store data for count_base_services calls + let mut services_ids_data = Vec::new(); // Store data for AnyServiceIds + let mut route_dispatch_data = Vec::new(); // Store data for route dispatches + + for (idx, impl_item) in self.program_impl.items.iter().enumerate() { + if let ImplItem::Fn(fn_item) = impl_item + && service_ctor_predicate(fn_item) + { + let (span, route, unwrap_result, _) = shared::invocation_export_or_default(fn_item); + let entry_id = routes.len() as u16; + if let Some(duplicate) = routes.insert(route.clone(), fn_item.sig.ident.to_string()) { - let (span, route, unwrap_result, _) = - shared::invocation_export_or_default(fn_item); - if let Some(duplicate) = - routes.insert(route.clone(), fn_item.sig.ident.to_string()) - { - abort!( - span, - "`export` attribute conflicts with one already assigned to '{}'", - duplicate - ); - } - return Some((idx, route, fn_item, unwrap_result)); + abort!( + span, + "`export` attribute conflicts with one already assigned to '{}'", + duplicate + ); } - None - }) - .map(|(idx, route, fn_item, unwrap_result)| { - let fn_builder = - FnBuilder::from(route, true, fn_item, unwrap_result, self.sails_path()); + + let fn_builder = FnBuilder::from( + route, + entry_id, + true, + fn_item, + unwrap_result, + self.sails_path(), + ); + let original_service_ctor_fn = fn_builder.original_service_ctor_fn(); let wrapping_service_ctor_fn = fn_builder.wrapping_service_ctor_fn(&original_service_ctor_fn.sig.ident); - services_route.push(fn_builder.service_const_route()); services_meta.push(fn_builder.service_meta()); if !has_async_ctor { - // If there are no async constructors, we can't push the asyncness as false, - // as there could be async handlers in services. meta_asyncness.push(fn_builder.service_meta_asyncness()); } - invocation_dispatches.push(fn_builder.service_invocation()); + #[cfg(feature = "ethexe")] solidity_dispatchers.push(fn_builder.sol_service_invocation()); - (idx, original_service_ctor_fn, wrapping_service_ctor_fn) - }) - .collect::>(); + // Extract data needed later (not the fn_builder itself) + let service_type = fn_builder.result_type.clone(); + let service_ctor_ident = fn_builder.ident.clone(); - if meta_asyncness.is_empty() { - // In case non of constructors is async and there are no services exposed. - meta_asyncness.push(quote!(false)); + services_count_data.push(service_type.clone()); + services_ids_data.push(service_type.clone()); + route_dispatch_data.push((service_ctor_ident, service_type)); + + modifications.push((idx, original_service_ctor_fn, wrapping_service_ctor_fn)); + } } - // replace service ctor fn impls - for (idx, original_service_ctor_fn, wrapping_service_ctor_fn, ..) in item_impl { + // Apply modifications to self - no more borrows from items after this point + for (idx, original_service_ctor_fn, wrapping_service_ctor_fn) in modifications { self.program_impl.items[idx] = ImplItem::Fn(original_service_ctor_fn); self.program_impl .items .push(ImplItem::Fn(wrapping_service_ctor_fn)); } + if meta_asyncness.is_empty() { + meta_asyncness.push(quote!(false)); + } + let handle_reply_fn = self.handle_reply_fn().map(|item_fn| { let handle_reply_fn_ident = &item_fn.sig.ident; quote! { @@ -238,8 +243,6 @@ impl ProgramBuilder { let (generics, program_type_constraints) = self.impl_constraints(); let program_meta_impl = quote! { - #(#services_route)* - impl #generics #sails_path::meta::ProgramMeta for #program_type_path #program_type_constraints { type ConstructorsMeta = meta_in_program::ConstructorsMeta; @@ -250,9 +253,84 @@ impl ProgramBuilder { } }; - invocation_dispatches.push(quote! { - { gstd::unknown_input_panic("Unexpected service", &input) } - }); + // Generate the INTERFACE_IDS registry using extracted data + let services_count_expr = { + let count_exprs = services_count_data.iter().map(|service_type| { + quote! { + + #sails_path::meta::count_base_services::<#service_type>() + } + }); + + let base_count = services_count_data.len(); + + quote! { + const SERVICES_COUNT: usize = #base_count #(#count_exprs)*; + } + }; + + let services_ids_expr = { + let ids_exprs = services_ids_data.iter().map(|service_type| { + quote! { + #sails_path::meta::BaseServiceMeta::new::<#service_type>(""), + } + }); + + quote! { + const INTERFACE_IDS: &'static [(#sails_path::meta::InterfaceId, u8)] = + &#sails_path::meta::interface_ids::(&[ + #(#ids_exprs)* + ]); + } + }; + + // Generate route_id match arms using extracted data + let route_dispatches = route_dispatch_data + .iter() + .enumerate() + .map(|(idx, (service_ctor_ident, service_type))| { + let route_id = (idx + 1) as u8; + + quote! { + #route_id => { + let svc = program_ref.#service_ctor_ident(); + let is_async = <#service_type as #sails_path::gstd::services::Service>::Exposure::check_asyncness(interface_id, entry_id) + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown call", &[]) + }); + if is_async { + gstd::message_loop(async move { + svc + .try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc + .try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic("Unknown request", &[])); + } + } + } + }) + .collect::>(); let solidity_main = self.sol_main(solidity_dispatchers.as_slice()); @@ -265,18 +343,34 @@ impl ProgramBuilder { }); let main_fn = quote!( + #services_count_expr + #services_ids_expr + #[unsafe(no_mangle)] extern "C" fn handle() { #payable let mut input = gstd::msg::load_bytes().expect("Failed to read input"); + + // let sails_message = gstd::msg::load::<#sails_path::SailsMessage>() + // .expect("Failed to read sails message"); + let program_ref = unsafe { #program_ident.as_mut() }.expect("Program not initialized"); #solidity_main - #(#invocation_dispatches)else*; + if let Ok(header) = <#sails_path::meta::SailsMessageHeader as #sails_path::Decode>::decode(&mut input.as_slice()) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + #(#route_dispatches)* + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]) + } + } } - ); let handle_reply_fn = quote! { @@ -339,33 +433,38 @@ impl ProgramBuilder { ctor_meta_variants.push(fn_builder.ctor_meta_variant()); } - ctor_dispatches.push(quote! { - { gstd::unknown_input_panic("Unexpected ctor", input) } - }); - let solidity_init = self.sol_init(&input_ident); + let sails_init = quote! { + if let Ok(header) = <#sails_path::meta::SailsMessageHeader as #sails_path::Decode>::decode(&mut #input_ident) { + if header.interface_id() != #sails_path::meta::InterfaceId::zero() { + #sails_path::gstd::unknown_input_panic("Non zero ctor interface_id", header.to_bytes().as_slice()); + } + match header.entry_id() { + #(#ctor_dispatches)* + _ => #sails_path::gstd::unknown_input_panic("Unexpected ctor entry_id", input), + } + } + }; + let init_fn = quote! { #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; - let mut #input_ident: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); #solidity_init - #(#ctor_dispatches)else*; + #sails_init } }; let meta_in_program = quote! { mod meta_in_program { use super::*; - use #sails_path::gstd::InvocationIo; #( #ctor_params_structs )* - #[derive(#sails_path ::TypeInfo)] + #[derive(#sails_path::TypeInfo)] #[scale_info(crate = #scale_info_path)] pub enum ConstructorsMeta { #( #ctor_meta_variants ),* @@ -482,11 +581,16 @@ fn discover_program_ctors<'a>( ) -> Vec> { let self_type_path: TypePath = parse_quote!(Self); let (program_type_path, _, _) = shared::impl_type_refs(program_impl.self_ty.as_ref()); - shared::discover_invocation_targets( + let mut vec = shared::discover_invocation_targets( program_impl, |fn_item| program_ctor_predicate(fn_item, &self_type_path, program_type_path), sails_path, - ) + ); + vec.sort_by_key(|f| f.route.to_lowercase()); + vec.iter_mut() + .enumerate() + .for_each(|(idx, f)| f.entry_id = idx as u16); + vec } fn program_ctor_predicate( @@ -547,13 +651,6 @@ fn handle_reply_predicate(fn_item: &ImplItemFn) -> bool { } impl FnBuilder<'_> { - fn route_ident(&self) -> Ident { - Ident::new( - &format!("__ROUTE_{}", self.route.to_ascii_uppercase()), - Span::call_site(), - ) - } - fn service_meta(&self) -> TokenStream2 { let sails_path = self.sails_path; let route = &self.route; @@ -566,51 +663,7 @@ impl FnBuilder<'_> { fn service_meta_asyncness(&self) -> TokenStream2 { let sails_path = self.sails_path; let service_type = &self.result_type; - quote!(< #service_type as #sails_path::meta::ServiceMeta>::ASYNC ) - } - - fn service_const_route(&self) -> TokenStream2 { - let route_ident = &self.route_ident(); - let ctor_route_bytes = self.encoded_route.as_slice(); - let ctor_route_len = ctor_route_bytes.len(); - quote!( - const #route_ident: [u8; #ctor_route_len] = [ #(#ctor_route_bytes),* ]; - ) - } - - fn service_invocation(&self) -> TokenStream2 { - let route_ident = &self.route_ident(); - let service_ctor_ident = self.ident; - quote! { - if input.starts_with(& #route_ident) { - let mut service = program_ref.#service_ctor_ident(); - let is_async = service - .check_asyncness(&input[#route_ident .len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown call", &input[#route_ident .len()..]) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async(&input[#route_ident .len()..], |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }) - .await - .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) - }); - }); - } else { - service - .try_handle(&input[#route_ident .len()..], |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }) - .unwrap_or_else(|| gstd::unknown_input_panic("Unknown request", &input)); - } - } - } + quote!(<#service_type as #sails_path::meta::ServiceMeta>::ASYNC ) } fn original_service_ctor_fn(&self) -> ImplItemFn { @@ -628,7 +681,7 @@ impl FnBuilder<'_> { fn wrapping_service_ctor_fn(&self, original_service_ctor_fn_ident: &Ident) -> ImplItemFn { let sails_path = self.sails_path; let service_type = &self.result_type; - let route_ident = &self.route_ident(); + let route_idx = (self.entry_id + 1) as u8; let unwrap_token = self.unwrap_result.then(|| quote!(.unwrap())); let mut wrapping_service_ctor_fn = self.impl_fn.clone(); @@ -643,7 +696,7 @@ impl FnBuilder<'_> { let service = self. #original_service_ctor_fn_ident () #unwrap_token; let exposure = < #service_type as #sails_path::gstd::services::Service>::expose( service, - #route_ident .as_ref(), + #route_idx, ); exposure }); @@ -656,13 +709,12 @@ impl FnBuilder<'_> { input_ident: &Ident, program_ident: &Ident, ) -> TokenStream2 { + let sails_path = self.sails_path; let handler_ident = self.ident; + let entry_id = self.entry_id; let unwrap_token = self.unwrap_result.then(|| quote!(.unwrap())); - let handler_args = self - .params_idents() - .iter() - .map(|ident| quote!(request.#ident)); - let params_struct_ident = &self.params_struct_ident; + let handler_args = self.params_idents(); + let handler_types = self.params_types(); let ctor_call_impl = if self.is_async() { quote! { gstd::message_loop(async move { @@ -683,7 +735,9 @@ impl FnBuilder<'_> { }; quote!( - if let Ok(request) = meta_in_program::#params_struct_ident::decode_params( #input_ident) { + #entry_id => { + let (#(#handler_args),*): (#(#handler_types),*) = #sails_path::Decode::decode(&mut #input_ident) + .unwrap_or_else(|_| #sails_path::gstd::unknown_input_panic("Unknown request", #input_ident)); #ctor_call_impl } ) @@ -693,22 +747,14 @@ impl FnBuilder<'_> { let sails_path = self.sails_path; let params_struct_ident = &self.params_struct_ident; let params_struct_members = self.params().map(|(ident, ty)| quote!(#ident: #ty)); - let ctor_route_bytes = self.encoded_route.as_slice(); - let is_async = self.is_async(); quote! { - #[derive(#sails_path ::Decode, #sails_path ::TypeInfo)] + #[derive(#sails_path::Decode, #sails_path::TypeInfo)] #[codec(crate = #scale_codec_path )] #[scale_info(crate = #scale_info_path )] pub struct #params_struct_ident { #(pub(super) #params_struct_members,)* } - - impl InvocationIo for #params_struct_ident { - const ROUTE: &'static [u8] = &[ #(#ctor_route_bytes),* ]; - type Params = Self; - const ASYNC: bool = #is_async; - } } } diff --git a/rs/macros/core/src/service/ethexe.rs b/rs/macros/core/src/service/ethexe.rs index fb890976..ff0f8e8f 100644 --- a/rs/macros/core/src/service/ethexe.rs +++ b/rs/macros/core/src/service/ethexe.rs @@ -11,7 +11,7 @@ impl ServiceBuilder<'_> { let service_method_expo = self .service_handlers .iter() - .map(|fn_builder| fn_builder.sol_handler_signature(true)); + .map(|fn_builder| fn_builder.sol_handler_signature(Some(service_type_path))); let combined_methods = if self.base_types.is_empty() { quote! { @@ -42,6 +42,7 @@ impl ServiceBuilder<'_> { pub(super) fn try_handle_solidity_impl(&self) -> TokenStream { let sails_path = self.sails_path; + let service_type_path = self.type_path; let inner_ident = &self.inner_ident; let impl_inner = |is_async: bool| { @@ -73,7 +74,7 @@ impl ServiceBuilder<'_> { Some(quote! { . #idx_literal }) }; quote! { - if let Some(result) = base_services #idx_token .expose(self.route) . #name_ident(method, input) #await_token { + if let Some(result) = base_services #idx_token .expose(self.route_idx) . #name_ident(interface_id, entry_id, input) #await_token { return Some(result); } } @@ -88,14 +89,21 @@ impl ServiceBuilder<'_> { quote! { pub #asyncness fn #name_ident( mut self, - method: &[u8], + interface_id: #sails_path::meta::InterfaceId, + entry_id: u16, input: &[u8], ) -> Option<(#sails_path::Vec, u128, bool)> { use #sails_path::gstd::services::{Service, Exposure}; - #( #service_method_branches )* - #base_invocation - None + if interface_id == ::INTERFACE_ID { + match entry_id { + #( #service_method_branches )* + _ => None, + } + } else { + #base_invocation + None + } } } }; @@ -127,16 +135,16 @@ impl ServiceBuilder<'_> { impl FnBuilder<'_> { /// Generates code /// ```rust - /// if method == &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] { + /// 0u16 => { /// // invocation /// } /// ``` fn sol_try_handle_branch_impl(&self) -> TokenStream { - let handler_route_bytes = self.encoded_route.as_slice(); + let entry_id = self.entry_id; let invocation = self.sol_invocation_func(); quote! { - if method == &[ #(#handler_route_bytes),* ] { + #entry_id => { #invocation } } diff --git a/rs/macros/core/src/service/exposure.rs b/rs/macros/core/src/service/exposure.rs index a612adec..6d6bde81 100644 --- a/rs/macros/core/src/service/exposure.rs +++ b/rs/macros/core/src/service/exposure.rs @@ -6,7 +6,7 @@ impl ServiceBuilder<'_> { pub(super) fn exposure_struct(&self) -> TokenStream { let sails_path = self.sails_path; let exposure_ident = &self.exposure_ident; - let route_ident = &self.route_ident; + let route_idx_ident = &self.route_idx_ident; let inner_ident = &self.inner_ident; let check_asyncness_impl = self.check_asyncness_impl(); @@ -23,13 +23,17 @@ impl ServiceBuilder<'_> { quote! { pub struct #exposure_ident { - #route_ident : &'static [u8], + #route_idx_ident : u8, #inner_ident : T, } impl #sails_path::gstd::services::Exposure for #exposure_ident { - fn route(&self) -> &'static [u8] { - self. #route_ident + fn interface_id() -> #sails_path::meta::InterfaceId { + T::INTERFACE_ID + } + + fn route_idx(&self) -> u8 { + self. #route_idx_ident } #check_asyncness_impl @@ -70,7 +74,6 @@ impl ServiceBuilder<'_> { } pub(super) fn exposure_impl(&self) -> TokenStream { - let sails_path = self.sails_path; let exposure_ident = &self.exposure_ident; let generics = &self.generics; let service_type_path = self.type_path; @@ -97,10 +100,6 @@ impl ServiceBuilder<'_> { impl #generics #exposure_ident< #service_type_path > #service_type_constraints { #( #exposure_funcs )* - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } - #try_handle_impl #try_handle_solidity_impl @@ -114,8 +113,10 @@ impl ServiceBuilder<'_> { pub(super) fn try_handle_impl(&self) -> TokenStream { let sails_path = self.sails_path; + let service_type_path = self.type_path; let inner_ident = &self.inner_ident; - let input_ident = &self.input_ident; + let meta_module_ident = &self.meta_module_ident; + let impl_inner = |is_async: bool| { let (name_ident, asyncness, await_token) = if is_async { ( @@ -127,9 +128,48 @@ impl ServiceBuilder<'_> { (quote!(try_handle), None, None) }; - let invocation_dispatches = self.service_handlers.iter().filter_map(|fn_builder| { + // Generate match arms for each handler's entry_id + let invocation_dispatches = self.service_handlers_with_ids.iter().filter_map(|(fn_builder, entry_id)| { if is_async == fn_builder.is_async() { - Some(fn_builder.try_handle_branch_impl(&self.meta_module_ident, input_ident)) + let handler_func_ident = fn_builder.ident; + let params_struct_ident = &fn_builder.params_struct_ident; + let handler_func_params = fn_builder + .params_idents() + .iter() + .map(|ident| quote!(request.#ident)); + + let (result_type, reply_with_value) = fn_builder.result_type_with_value(); + let unwrap_token = fn_builder.unwrap_result.then(|| quote!(.unwrap())); + + let handle_token = if reply_with_value { + quote! { + let command_reply: CommandReply< #result_type > = self.#handler_func_ident(#(#handler_func_params),*)#await_token #unwrap_token.into(); + let (result, value) = command_reply.to_tuple(); + } + } else { + quote! { + let result = self.#handler_func_ident(#(#handler_func_params),*)#await_token #unwrap_token; + let value = 0u128; + } + }; + + let result_type_static = fn_builder.result_type_with_static_lifetime(); + + Some(quote! { + #entry_id => { + let request: #meta_module_ident::#params_struct_ident = #sails_path::scale_codec::Decode::decode(&mut input) + .expect("Failed to decode params"); + #handle_token + if ! #sails_path::gstd::is_empty_tuple::<#result_type_static>() { + <#meta_module_ident::#params_struct_ident as #sails_path::gstd::InvocationIo>::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + }) } else { None } @@ -138,18 +178,39 @@ impl ServiceBuilder<'_> { let base_invocation = if self.base_types.is_empty() { None } else { + // Sort base services lexicographically + let mut base_services_with_index: Vec<_> = self + .base_types + .iter() + .enumerate() + .map(|(idx, base_type)| (idx, base_type, shared::remove_lifetimes(base_type))) + .collect(); + + base_services_with_index.sort_by_key(|(_, _, path_wo_lifetimes)| { + path_wo_lifetimes + .segments + .last() + .expect("Base service path should have at least one segment") + .ident + .to_string() + .to_lowercase() + }); + let base_types = self.base_types; - let base_exposure_invocations = base_types.iter().enumerate().map(|(idx, _)| { - let idx_token = if base_types.len() == 1 { None } else { - let idx_literal = Literal::usize_unsuffixed(idx); + let base_exposure_invocations = base_services_with_index.iter().map(|(idx, _, _)| { + let idx_token = if base_types.len() == 1 { + None + } else { + let idx_literal = Literal::usize_unsuffixed(*idx); Some(quote! { . #idx_literal }) }; quote! { - if base_services #idx_token .expose(self.route) . #name_ident(#input_ident, result_handler) #await_token.is_some() { + if #sails_path::gstd::services::Service::expose(base_services #idx_token, self.route_idx) . #name_ident(interface_id, entry_id, input, result_handler) #await_token.is_some() { return Some(()); } } }); + // Base Services, as `Into` tuple from Service Some(quote! { let base_services: ( #( #base_types ),* ) = self. #inner_ident .into(); @@ -158,12 +219,25 @@ impl ServiceBuilder<'_> { }; quote! { - pub #asyncness fn #name_ident(mut self, #input_ident : &[u8], result_handler: fn(&[u8], u128)) -> Option<()> { - use #sails_path::gstd::InvocationIo; - use #sails_path::gstd::services::{Service, Exposure}; - #( #invocation_dispatches )* - #base_invocation - None + pub #asyncness fn #name_ident( + mut self, + interface_id: #sails_path::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], + result_handler: fn(&[u8], u128) + ) -> Option<()> { + use #sails_path::gstd::services::{Exposure, Service}; + use #sails_path::gstd::{InvocationIo, CommandReply}; + + if interface_id == ::INTERFACE_ID { + match entry_id { + #( #invocation_dispatches )* + _ => None, + } + } else { + #base_invocation + None + } } } }; @@ -184,16 +258,16 @@ impl ServiceBuilder<'_> { let service_type_path = self.type_path; let service_type_constraints = self.type_constraints(); - let route_ident = &self.route_ident; + let route_idx_ident = &self.route_idx_ident; let inner_ident = &self.inner_ident; quote!( impl #generics #sails_path::gstd::services::Service for #service_type_path #service_type_constraints { type Exposure = #exposure_ident; - fn expose(self, #route_ident : &'static [u8]) -> Self::Exposure { + fn expose(self, #route_idx_ident : u8) -> Self::Exposure { Self::Exposure { - #route_ident , + #route_idx_ident , #inner_ident : self, } } @@ -203,7 +277,6 @@ impl ServiceBuilder<'_> { fn check_asyncness_impl(&self) -> TokenStream { let sails_path = self.sails_path; - let input_ident = &self.input_ident; // Here `T` is Service Type let service_asyncness_check = quote! { @@ -215,31 +288,54 @@ impl ServiceBuilder<'_> { } }; - let asyncness_checks = self.service_handlers.iter().map(|fn_builder| { - fn_builder.check_asyncness_branch_impl(&self.meta_module_ident, input_ident) + // Generate match arms for each handler's entry_id + let asyncness_checks = + self.service_handlers_with_ids + .iter() + .map(|(fn_builder, entry_id)| { + let is_async = fn_builder.is_async(); + quote! { + #entry_id => Some(#is_async), + } + }); + + // Sort base services lexicographically + let mut base_services_sorted = self + .base_types + .iter() + .map(shared::remove_lifetimes) + .collect::>(); + base_services_sorted.sort_by_key(|path_wo_lifetimes| { + path_wo_lifetimes + .segments + .last() + .expect("Base service path should have at least one segment") + .ident + .to_string() + .to_lowercase() }); - let base_services_asyncness_checks = self.base_types.iter().map(|base_type| { - let path_wo_lifetimes = shared::remove_lifetimes(base_type); + let base_services_asyncness_checks = base_services_sorted.iter().map(|base_type| { quote! { - if let Some(is_async) = <<#path_wo_lifetimes as Service>::Exposure as Exposure>::check_asyncness(#input_ident) { + if let Some(is_async) = <<#base_type as #sails_path::gstd::services::Service>::Exposure as #sails_path::gstd::services::Exposure>::check_asyncness(interface_id, entry_id) { return Some(is_async); } } }); quote! { - fn check_asyncness(#input_ident : &[u8]) -> Option { - use #sails_path::gstd::InvocationIo; - use #sails_path::gstd::services::{Service, Exposure}; - + fn check_asyncness(interface_id: #sails_path::meta::InterfaceId, entry_id: u16) -> Option { #service_asyncness_check - #( #asyncness_checks )* - - #( #base_services_asyncness_checks )* - - None + if interface_id == T::INTERFACE_ID { + match entry_id { + #( #asyncness_checks )* + _ => None, + } + } else { + #( #base_services_asyncness_checks )* + None + } } } } diff --git a/rs/macros/core/src/service/meta.rs b/rs/macros/core/src/service/meta.rs index 06d1871b..8429d77a 100644 --- a/rs/macros/core/src/service/meta.rs +++ b/rs/macros/core/src/service/meta.rs @@ -1,7 +1,7 @@ use super::*; use proc_macro2::TokenStream; use quote::quote; -use std::collections::HashSet; +use std::collections::BTreeSet; impl ServiceBuilder<'_> { pub(super) fn meta_trait_impl(&self) -> TokenStream { @@ -9,10 +9,9 @@ impl ServiceBuilder<'_> { let generics = &self.generics; let service_type_path = self.type_path; let service_type_constraints = self.type_constraints(); - let meta_module_ident = &self.meta_module_ident; // TODO [future]: remove the duplicates check for the Sails binary protocol - let mut base_names = HashSet::new(); + let mut base_names = BTreeSet::new(); let base_services_meta = self.base_types.iter().map(|base_type| { let path_wo_lifetimes = shared::remove_lifetimes(base_type); let base_type_pathless_name = path_wo_lifetimes @@ -24,13 +23,14 @@ impl ServiceBuilder<'_> { if !base_names.insert(base_type_pathless_name.clone()) { abort!( - base_type, "Base service with the same name was defined - `{}`", + base_type, + "Base service with the same name was defined - `{}`", base_type_pathless_name ); } quote! { - (#base_type_pathless_name , #sails_path::meta::AnyServiceMeta::new::< #path_wo_lifetimes >) + #sails_path::meta::BaseServiceMeta::new::< super:: #path_wo_lifetimes >( #base_type_pathless_name ) } }); @@ -46,8 +46,9 @@ impl ServiceBuilder<'_> { } else { let base_asyncness = self.base_types.iter().map(|base_type| { let path_wo_lifetimes = shared::remove_lifetimes(base_type); + quote! { - <#path_wo_lifetimes as #sails_path::meta::ServiceMeta>::ASYNC + ::ASYNC } }); quote!(#( #base_asyncness )||*) @@ -56,11 +57,11 @@ impl ServiceBuilder<'_> { let interface_id_computation = self.generate_interface_id(); quote! { - impl #generics #sails_path::meta::ServiceMeta for #service_type_path #service_type_constraints { - type CommandsMeta = #meta_module_ident::CommandsMeta; - type QueriesMeta = #meta_module_ident::QueriesMeta; - type EventsMeta = #meta_module_ident::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, #sails_path::meta::AnyServiceMetaFn)] = &[ + impl #generics #sails_path::meta::ServiceMeta for super:: #service_type_path #service_type_constraints { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [#sails_path::meta::BaseServiceMeta] = &[ #( #base_services_meta ),* ]; const ASYNC: bool = #service_meta_asyncness ; @@ -78,10 +79,9 @@ impl ServiceBuilder<'_> { let no_events_type = Path::from(Ident::new("NoEvents", Span::call_site())); let events_type = self.events_type.unwrap_or(&no_events_type); - let invocation_params_structs = self - .service_handlers - .iter() - .map(|fn_builder| fn_builder.params_struct(scale_codec_path, scale_info_path)); + let invocation_params_structs = self.service_handlers.iter().map(|fn_builder| { + fn_builder.params_struct(self.type_path, scale_codec_path, scale_info_path) + }); let commands_meta_variants = self.service_handlers.iter().filter_map(|fn_builder| { (!fn_builder.is_query()).then_some(fn_builder.handler_meta_variant()) }); @@ -89,27 +89,29 @@ impl ServiceBuilder<'_> { (fn_builder.is_query()).then_some(fn_builder.handler_meta_variant()) }); + let meta_trait_impl = self.meta_trait_impl(); + quote! { mod #meta_module_ident { use super::*; - use #sails_path::{Decode, TypeInfo}; - use #sails_path::gstd::InvocationIo; + + #meta_trait_impl #( #invocation_params_structs )* - #[derive(TypeInfo)] + #[derive(#sails_path::TypeInfo)] #[scale_info(crate = #scale_info_path)] pub enum CommandsMeta { #(#commands_meta_variants),* } - #[derive(TypeInfo)] + #[derive(#sails_path::TypeInfo)] #[scale_info(crate = #scale_info_path)] pub enum QueriesMeta { #(#queries_meta_variants),* } - #[derive(TypeInfo)] + #[derive(#sails_path::TypeInfo)] #[scale_info(crate = #scale_info_path )] pub enum #no_events_type {} @@ -128,48 +130,31 @@ impl ServiceBuilder<'_> { commands.sort_by_key(|h| h.route.to_lowercase()); queries.sort_by_key(|h| h.route.to_lowercase()); - // TODO: #1124 let fn_hash_computations: Vec<_> = commands .into_iter() .chain(queries) .map(|handler| { - let fn_type = if handler.is_query() { "query" } else { "command" }; - let fn_name = &handler.route; + let fn_type = if handler.is_query() { quote! { query } } else { quote! { command } }; + let fn_name = Ident::new(&handler.route, Span::call_site()); - // Generate ARG_HASH = REFLECT_HASH for each argument - let arg_hash_computations = handler.params().map(|(_, ty)| { - quote!(fn_hash = fn_hash.update(&<#ty as #sails_path::sails_reflect_hash::ReflectHash>::HASH);) - }); + let arg_types = handler.params().map(|(_, ty)| ty); // Generate RES_HASH - check if result type is Result let result_type = handler.result_type_with_static_lifetime(); - let result_hash = if let Type::Path(ref tp) = result_type && let Some((ok_ty, err_ty)) = shared::extract_result_types(tp) { + let result_tokens = if handler.unwrap_result + && let Type::Path(ref tp) = result_type + && let Some((ok_ty, err_ty)) = shared::extract_result_types(tp) { // Result type: RES_HASH = b"res" || T::HASH || b"throws" || E::HASH - quote! { - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash.update(&<#ok_ty as #sails_path::sails_reflect_hash::ReflectHash>::HASH); - fn_hash = fn_hash.update(b"throws"); - fn_hash = fn_hash.update(&<#err_ty as #sails_path::sails_reflect_hash::ReflectHash>::HASH); - } + quote!( -> #ok_ty | #err_ty ) } else { // Other types: RES_HASH = b"res" || REFLECT_HASH - quote! { - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash.update(&<#result_type as #sails_path::sails_reflect_hash::ReflectHash>::HASH); - } + quote!( -> #result_type ) }; // FN_HASH = hash(bytes(FN_TYPE) || bytes(FN_NAME) || ARGS_REFLECT_HASH || RES_HASH) // RES_HASH = (b"res" || REFLECT_HASH) | (b"res" || T_REFLECT_HASH || bytes("throws") || E_REFLECT_HASH) quote! { - { - let mut fn_hash = #sails_path::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update(#fn_type.as_bytes()); - fn_hash = fn_hash.update(#fn_name.as_bytes()); - #(#arg_hash_computations)* - #result_hash - final_hash = final_hash.update(&fn_hash.finalize()); - } + final_hash = final_hash.update(& #sails_path::hash_fn!( #fn_type #fn_name ( #( #arg_types ),* ) #result_tokens )); } }) .collect(); @@ -199,7 +184,7 @@ impl ServiceBuilder<'_> { }); let base_service_ids = base_services.into_iter().map(|base_type_no_lifetime| { - quote!(final_hash = final_hash.update(&<#base_type_no_lifetime as #sails_path::meta::ServiceMeta>::INTERFACE_ID.0);) + quote!(final_hash = final_hash.update(&::INTERFACE_ID.0);) }); quote!(#(#base_service_ids)*) diff --git a/rs/macros/core/src/service/mod.rs b/rs/macros/core/src/service/mod.rs index 37179656..8c55ea70 100644 --- a/rs/macros/core/src/service/mod.rs +++ b/rs/macros/core/src/service/mod.rs @@ -65,10 +65,11 @@ struct ServiceBuilder<'a> { type_path: &'a TypePath, events_type: Option<&'a Path>, service_handlers: Vec>, + /// Handlers with assigned entry IDs (sorted: commands then queries) + service_handlers_with_ids: Vec<(FnBuilder<'a>, u16)>, exposure_ident: Ident, - route_ident: Ident, + route_idx_ident: Ident, inner_ident: Ident, - input_ident: Ident, meta_module_ident: Ident, } @@ -82,14 +83,17 @@ impl<'a> ServiceBuilder<'a> { let (type_path, _type_args, service_ident) = shared::impl_type_refs(service_impl.self_ty.as_ref()); let service_handlers = discover_service_handlers(service_impl, sails_path); + + // Assign entry IDs: commands (sorted) get 0..N-1, queries (sorted) get N..M-1 + let service_handlers_with_ids = Self::assign_entry_ids(&service_handlers); + let exposure_name = format!( "{}Exposure", service_ident.to_string().to_case(Case::Pascal) ); let exposure_ident = Ident::new(&exposure_name, Span::call_site()); - let route_ident = Ident::new("route", Span::call_site()); + let route_idx_ident = Ident::new("route_idx", Span::call_site()); let inner_ident = Ident::new("inner", Span::call_site()); - let input_ident = Ident::new("input", Span::call_site()); let meta_module_name = format!("{}_meta", service_ident.to_string().to_case(Case::Snake)); let meta_module_ident = Ident::new(&meta_module_name, Span::call_site()); @@ -102,14 +106,38 @@ impl<'a> ServiceBuilder<'a> { type_path, events_type: service_args.events_type(), service_handlers, + service_handlers_with_ids, exposure_ident, - route_ident, + route_idx_ident, inner_ident, - input_ident, meta_module_ident, } } + fn assign_entry_ids(handlers: &[FnBuilder<'a>]) -> Vec<(FnBuilder<'a>, u16)> { + let (mut commands, mut queries): (Vec<_>, Vec<_>) = + handlers.iter().partition(|h| !h.is_query()); + + // Sort by name (lowercase for case-insensitive) + commands.sort_by_key(|h| h.route.to_lowercase()); + queries.sort_by_key(|h| h.route.to_lowercase()); + + let mut result = Vec::new(); + let mut entry_id = 0u16; + + for cmd in commands { + result.push((cmd.clone(), entry_id)); + entry_id += 1; + } + + for query in queries { + result.push((query.clone(), entry_id)); + entry_id += 1; + } + + result + } + fn type_constraints(&self) -> Option<&WhereClause> { self.type_constraints.as_ref() } @@ -149,7 +177,6 @@ fn generate_gservice(args: TokenStream, service_impl: ItemImpl) -> TokenStream { ); } - let meta_trait_impl = service_builder.meta_trait_impl(); let meta_module = service_builder.meta_module(); let exposure_struct = service_builder.exposure_struct(); @@ -166,8 +193,6 @@ fn generate_gservice(args: TokenStream, service_impl: ItemImpl) -> TokenStream { #service_trait_impl - #meta_trait_impl - #meta_module #service_signature_impl @@ -178,14 +203,20 @@ fn discover_service_handlers<'a>( service_impl: &'a ItemImpl, sails_path: &'a Path, ) -> Vec> { - shared::discover_invocation_targets( + let mut vec: Vec<_> = shared::discover_invocation_targets( service_impl, |fn_item| matches!(fn_item.vis, Visibility::Public(_)) && fn_item.sig.receiver().is_some(), sails_path, ) .into_iter() .filter(|fn_builder| fn_builder.export) - .collect() + .collect(); + // service funcs ordered by (fn_type, name) + vec.sort_by_key(|f| (f.is_query(), f.route.to_lowercase())); + vec.iter_mut() + .enumerate() + .for_each(|(idx, f)| f.entry_id = idx as u16); + vec } impl FnBuilder<'_> { @@ -211,86 +242,33 @@ impl FnBuilder<'_> { ) } - fn params_struct(&self, scale_codec_path: &Path, scale_info_path: &Path) -> TokenStream { + fn params_struct( + &self, + service_path: &TypePath, + scale_codec_path: &Path, + scale_info_path: &Path, + ) -> TokenStream { + let sails_path = self.sails_path; let params_struct_ident = &self.params_struct_ident; let params_struct_members = self.params().map(|(ident, ty)| quote!(#ident: #ty)); - let handler_route_bytes = self.encoded_route.as_slice(); - let is_async = self.is_async(); + let entry_id = &self.entry_id; + let path_wo_lifetimes = shared::remove_lifetimes(&service_path.path); quote!( - #[derive(Decode, TypeInfo)] + #[derive(#sails_path::Decode, #sails_path::TypeInfo)] #[codec(crate = #scale_codec_path )] #[scale_info(crate = #scale_info_path )] pub struct #params_struct_ident { #(pub(super) #params_struct_members,)* } - impl InvocationIo for #params_struct_ident { - const ROUTE: &'static [u8] = &[ #(#handler_route_bytes),* ]; + impl #sails_path::gstd::InvocationIo for #params_struct_ident { + const INTERFACE_ID: #sails_path::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = #entry_id; type Params = Self; - const ASYNC: bool = #is_async; } ) } - - fn try_handle_branch_impl( - &self, - meta_module_ident: &Ident, - input_ident: &Ident, - ) -> TokenStream { - let handler_func_ident = self.ident; - - let params_struct_ident = &self.params_struct_ident; - let handler_func_params = self - .params_idents() - .iter() - .map(|ident| quote!(request.#ident)); - - let (result_type, reply_with_value) = self.result_type_with_value(); - let await_token = self.is_async().then(|| quote!(.await)); - let unwrap_token = self.unwrap_result.then(|| quote!(.unwrap())); - - let handle_token = if reply_with_value { - quote! { - let command_reply: CommandReply< #result_type > = self.#handler_func_ident(#(#handler_func_params),*)#await_token #unwrap_token.into(); - let (result, value) = command_reply.to_tuple(); - } - } else { - quote! { - let result = self.#handler_func_ident(#(#handler_func_params),*)#await_token #unwrap_token; - let value = 0u128; - } - }; - - let result_type = self.result_type_with_static_lifetime(); - quote! { - if let Ok(request) = #meta_module_ident::#params_struct_ident::decode_params( #input_ident) { - #handle_token - if !#meta_module_ident::#params_struct_ident::is_empty_tuple::<#result_type>() { - #meta_module_ident::#params_struct_ident::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - } - } - - fn check_asyncness_branch_impl( - &self, - meta_module_ident: &Ident, - input_ident: &Ident, - ) -> TokenStream { - let params_struct_ident = &self.params_struct_ident; - - quote! { - if let Ok(is_async) = #meta_module_ident::#params_struct_ident::check_asyncness( #input_ident) { - return Some(is_async); - } - } - } } #[cfg(test)] @@ -325,13 +303,13 @@ mod tests { .unwrap(); let sails_path = &sails_paths::sails_path_or_default(None); - let discovered_ctors = discover_service_handlers(&service_impl, sails_path) + let discovered_svcs = discover_service_handlers(&service_impl, sails_path) .iter() .map(|fn_builder| fn_builder.ident.to_string()) .collect::>(); assert_eq!( - discovered_ctors, + discovered_svcs, &[ "export_public_method_returning_self", "export_public_method_returning_smth", diff --git a/rs/macros/core/src/shared.rs b/rs/macros/core/src/shared.rs index 6edf3c78..ec5ee26f 100644 --- a/rs/macros/core/src/shared.rs +++ b/rs/macros/core/src/shared.rs @@ -1,6 +1,5 @@ use crate::export; use convert_case::{Case, Casing}; -use parity_scale_codec::Encode; use proc_macro_error::abort; use proc_macro2::Span; use quote::ToTokens; @@ -106,7 +105,7 @@ pub(crate) fn discover_invocation_targets<'a>( sails_path: &'a Path, ) -> Vec> { let mut routes = BTreeMap::::new(); - let mut vec: Vec> = item_impl + let vec: Vec> = item_impl .items .iter() .filter_map(|item| { @@ -114,7 +113,8 @@ pub(crate) fn discover_invocation_targets<'a>( && filter(fn_item) { let (span, route, unwrap_result, export) = invocation_export_or_default(fn_item); - + // `entry_id` in order of appearance + let entry_id = routes.len() as u16; if let Some(duplicate) = routes.insert(route.clone(), fn_item.sig.ident.to_string()) { abort!( @@ -123,13 +123,13 @@ pub(crate) fn discover_invocation_targets<'a>( duplicate ); } - let fn_builder = FnBuilder::from(route, export, fn_item, unwrap_result, sails_path); + let fn_builder = + FnBuilder::from(route, entry_id, export, fn_item, unwrap_result, sails_path); return Some(fn_builder); } None }) .collect(); - vec.sort_by(|a, b| a.route.cmp(&b.route)); vec } @@ -270,8 +270,8 @@ pub(crate) fn extract_result_types(tp: &TypePath) -> Option<(&Type, &Type)> { #[derive(Clone)] pub(crate) struct FnBuilder<'a> { pub route: String, + pub entry_id: u16, pub export: bool, - pub encoded_route: Vec, pub impl_fn: &'a ImplItemFn, pub ident: &'a Ident, pub params_struct_ident: Ident, @@ -285,12 +285,12 @@ pub(crate) struct FnBuilder<'a> { impl<'a> FnBuilder<'a> { pub(crate) fn from( route: String, + entry_id: u16, export: bool, impl_fn: &'a ImplItemFn, unwrap_result: bool, sails_path: &'a Path, ) -> Self { - let encoded_route = route.encode(); let signature = &impl_fn.sig; let ident = &signature.ident; let params_struct_ident = Ident::new(&format!("__{route}Params"), Span::call_site()); @@ -299,8 +299,8 @@ impl<'a> FnBuilder<'a> { Self { route, + entry_id, export, - encoded_route, impl_fn, ident, params_struct_ident, @@ -345,7 +345,6 @@ impl<'a> FnBuilder<'a> { self.params_idents.as_slice() } - #[cfg(feature = "ethexe")] pub(crate) fn params_types(&self) -> &[&Type] { self.params_types.as_slice() } diff --git a/rs/macros/core/tests/event.rs b/rs/macros/core/tests/event.rs index ce0fa72d..5feeae01 100644 --- a/rs/macros/core/tests/event.rs +++ b/rs/macros/core/tests/event.rs @@ -35,3 +35,22 @@ fn event_sails_rename() { insta::assert_snapshot!(result); } + +#[test] +fn event_sort_by_name() { + let input = quote! { + pub enum Events { + MyEvent2(u128, u128, String), + MyEvent1 { + sender: u128, + amount: u128, + note: String, + }, + MyEvent3, + } + }; + let result = event(quote!(), input).to_string(); + let result = prettyplease::unparse(&syn::parse_str(&result).unwrap()); + + insta::assert_snapshot!(result); +} diff --git a/rs/macros/core/tests/gservice.rs b/rs/macros/core/tests/gservice.rs index f477f575..fceed403 100644 --- a/rs/macros/core/tests/gservice.rs +++ b/rs/macros/core/tests/gservice.rs @@ -9,8 +9,8 @@ fn works_with_basics() { let input = quote! { impl SomeService { #[export] - pub async fn do_this(&mut self, p1: u32, p2: String) -> u32 { - p1 + pub async fn do_this(&mut self, p1: u32, p2: String) -> String { + format!("{p1}: ") + &p2 } #[export] diff --git a/rs/macros/core/tests/snapshots/event__event_basic.snap b/rs/macros/core/tests/snapshots/event__event_basic.snap index ee40edd7..63e4a432 100644 --- a/rs/macros/core/tests/snapshots/event__event_basic.snap +++ b/rs/macros/core/tests/snapshots/event__event_basic.snap @@ -13,6 +13,11 @@ impl sails_rs::SailsEvent for MyEvent { } } } + fn entry_id(&self) -> u16 { + match self { + MyEvent::MyEvent1 => 0u16, + } + } fn skip_bytes() -> usize { 1 } diff --git a/rs/macros/core/tests/snapshots/event__event_sails_rename.snap b/rs/macros/core/tests/snapshots/event__event_sails_rename.snap index aecc6df3..cc9b2e82 100644 --- a/rs/macros/core/tests/snapshots/event__event_sails_rename.snap +++ b/rs/macros/core/tests/snapshots/event__event_sails_rename.snap @@ -21,6 +21,13 @@ impl sails_rename::SailsEvent for Events { } } } + fn entry_id(&self) -> u16 { + match self { + Events::MyEvent1 { .. } => 0u16, + Events::MyEvent2(..) => 1u16, + Events::MyEvent3 => 2u16, + } + } fn skip_bytes() -> usize { 1 } diff --git a/rs/macros/core/tests/snapshots/event__event_sort_by_name.snap b/rs/macros/core/tests/snapshots/event__event_sort_by_name.snap new file mode 100644 index 00000000..c2900564 --- /dev/null +++ b/rs/macros/core/tests/snapshots/event__event_sort_by_name.snap @@ -0,0 +1,34 @@ +--- +source: rs/macros/core/tests/event.rs +expression: result +--- +pub enum Events { + MyEvent1 { sender: u128, amount: u128, note: String }, + MyEvent2(u128, u128, String), + MyEvent3, +} +impl sails_rs::SailsEvent for Events { + fn encoded_event_name(&self) -> &'static [u8] { + match self { + Events::MyEvent1 { .. } => { + &[32u8, 77u8, 121u8, 69u8, 118u8, 101u8, 110u8, 116u8, 49u8] + } + Events::MyEvent2(..) => { + &[32u8, 77u8, 121u8, 69u8, 118u8, 101u8, 110u8, 116u8, 50u8] + } + Events::MyEvent3 => { + &[32u8, 77u8, 121u8, 69u8, 118u8, 101u8, 110u8, 116u8, 51u8] + } + } + } + fn entry_id(&self) -> u16 { + match self { + Events::MyEvent1 { .. } => 0u16, + Events::MyEvent2(..) => 1u16, + Events::MyEvent3 => 2u16, + } + } + fn skip_bytes() -> usize { + 1 + } +} diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_async_ctor_with_service.snap b/rs/macros/core/tests/snapshots/gprogram__generates_async_ctor_with_service.snap index 45e557a0..6b611ba8 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_async_ctor_with_service.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_async_ctor_with_service.snap @@ -13,14 +13,11 @@ impl MyProgram { let service = self.__service(); let exposure = ::expose( service, - __ROUTE_SERVICE.as_ref(), + 1u8, ); exposure } } -const __ROUTE_SERVICE: [u8; 8usize] = [ - 28u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -30,7 +27,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -38,11 +34,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -56,65 +47,101 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } + } } + const SERVICES_COUNT: usize = 1usize + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[sails_rs::meta::BaseServiceMeta::new::("")]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - if input.starts_with(&__ROUTE_SERVICE) { - let mut service = program_ref.service(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_async_main_with_handle_reply.snap b/rs/macros/core/tests/snapshots/gprogram__generates_async_main_with_handle_reply.snap index d5b7f5c4..33c2475a 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_async_main_with_handle_reply.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_async_main_with_handle_reply.snap @@ -15,16 +15,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -38,22 +32,57 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_ctors_meta_with_docs.snap b/rs/macros/core/tests/snapshots/gprogram__generates_ctors_meta_with_docs.snap index c5586cab..7167cdf3 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_ctors_meta_with_docs.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_ctors_meta_with_docs.snap @@ -20,7 +20,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -28,11 +27,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -40,11 +34,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -62,29 +51,70 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_multiple_services_with_non_empty_routes.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_multiple_services_with_non_empty_routes.snap index c79ed635..3c2daa8a 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_multiple_services_with_non_empty_routes.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_multiple_services_with_non_empty_routes.snap @@ -18,7 +18,7 @@ impl MyProgram { let service = self.__service1(); let exposure = ::expose( service, - __ROUTE_SVC1.as_ref(), + 1u8, ); exposure } @@ -28,15 +28,11 @@ impl MyProgram { let service = self.__service2(); let exposure = ::expose( service, - __ROUTE_SERVICE2.as_ref(), + 2u8, ); exposure } } -const __ROUTE_SVC1: [u8; 5usize] = [16u8, 83u8, 118u8, 99u8, 49u8]; -const __ROUTE_SERVICE2: [u8; 9usize] = [ - 32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -48,16 +44,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -71,102 +61,146 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 2usize + + sails_rs::meta::count_base_services::() + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >( + &[ + sails_rs::meta::BaseServiceMeta::new::(""), + sails_rs::meta::BaseServiceMeta::new::(""), + ], + ); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - if input.starts_with(&__ROUTE_SVC1) { - let mut service = program_ref.service1(); - let is_async = service - .check_asyncness(&input[__ROUTE_SVC1.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SVC1.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service1(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); - } - } else if input.starts_with(&__ROUTE_SERVICE2) { - let mut service = program_ref.service2(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE2.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE2.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + 2u8 => { + let svc = program_ref.service2(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_services_with_unwrap_result.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_services_with_unwrap_result.snap index 9f607865..9490a573 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_services_with_unwrap_result.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_services_with_unwrap_result.snap @@ -18,7 +18,7 @@ impl MyProgram { let service = self.__service1().unwrap(); let exposure = ::expose( service, - __ROUTE_SVC1.as_ref(), + 1u8, ); exposure } @@ -28,15 +28,11 @@ impl MyProgram { let service = self.__service2(); let exposure = ::expose( service, - __ROUTE_SERVICE2.as_ref(), + 2u8, ); exposure } } -const __ROUTE_SVC1: [u8; 5usize] = [16u8, 83u8, 118u8, 99u8, 49u8]; -const __ROUTE_SERVICE2: [u8; 9usize] = [ - 32u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 50u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -48,16 +44,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -71,102 +61,146 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 2usize + + sails_rs::meta::count_base_services::() + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >( + &[ + sails_rs::meta::BaseServiceMeta::new::(""), + sails_rs::meta::BaseServiceMeta::new::(""), + ], + ); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - if input.starts_with(&__ROUTE_SVC1) { - let mut service = program_ref.service1(); - let is_async = service - .check_asyncness(&input[__ROUTE_SVC1.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SVC1.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service1(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SVC1.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); - } - } else if input.starts_with(&__ROUTE_SERVICE2) { - let mut service = program_ref.service2(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE2.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE2.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + 2u8 => { + let svc = program_ref.service2(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE2.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_single_service_with_non_empty_route.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_single_service_with_non_empty_route.snap index acd6fbaf..89d5cd13 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_single_service_with_non_empty_route.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_for_single_service_with_non_empty_route.snap @@ -13,14 +13,11 @@ impl MyProgram { let service = self.__service(); let exposure = ::expose( service, - __ROUTE_SERVICE.as_ref(), + 1u8, ); exposure } } -const __ROUTE_SERVICE: [u8; 8usize] = [ - 28u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, -]; impl sails_rs::meta::ProgramMeta for MyProgram { type ConstructorsMeta = meta_in_program::ConstructorsMeta; const SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ @@ -30,16 +27,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -53,63 +44,99 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 1usize + + sails_rs::meta::count_base_services::(); + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[sails_rs::meta::BaseServiceMeta::new::("")]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - if input.starts_with(&__ROUTE_SERVICE) { - let mut service = program_ref.service(); - let is_async = service - .check_asyncness(&input[__ROUTE_SERVICE.len()..]) - .unwrap_or_else(|| { - gstd::unknown_input_panic( - "Unknown call", - &input[__ROUTE_SERVICE.len()..], - ) - }); - if is_async { - gstd::message_loop(async move { - service - .try_handle_async( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + 1u8 => { + let svc = program_ref.service(); + let is_async = ::Exposure::check_asyncness( + interface_id, + entry_id, ) - .await .unwrap_or_else(|| { - gstd::unknown_input_panic("Unknown request", &input) + gstd::unknown_input_panic("Unknown call", &[]) }); - }); - } else { - service - .try_handle( - &input[__ROUTE_SERVICE.len()..], - |encoded_result, value| { - gstd::msg::reply_bytes(encoded_result, value) - .expect("Failed to send output"); - }, - ) - .unwrap_or_else(|| gstd::unknown_input_panic( - "Unknown request", - &input, - )); + if is_async { + gstd::message_loop(async move { + svc.try_handle_async( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .await + .unwrap_or_else(|| { + gstd::unknown_input_panic("Unknown request", &[]) + }); + }); + } else { + svc.try_handle( + interface_id, + entry_id, + &input[header_len..], + |encoded_result, value| { + gstd::msg::reply_bytes(encoded_result, value) + .expect("Failed to send output"); + }, + ) + .unwrap_or_else(|| gstd::unknown_input_panic( + "Unknown request", + &[], + )); + } + } + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), } - } else { - gstd::unknown_input_panic("Unexpected service", &input) - }; + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_crate_path.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_crate_path.snap index 59de8dd8..832e1844 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_crate_path.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_crate_path.snap @@ -14,16 +14,10 @@ impl sails_rename::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rename::gstd::InvocationIo; #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum ConstructorsMeta { @@ -37,22 +31,57 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rename::meta::InterfaceId::zero() { + sails_rename::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rename::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rename::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rename::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rename::meta::InterfaceId, u8)] = &sails_rename::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_gprogram_attributes.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_gprogram_attributes.snap index 0ad24aca..41f80efe 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_gprogram_attributes.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_gprogram_attributes.snap @@ -14,16 +14,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -37,22 +31,57 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_payable.snap b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_payable.snap index 2308d9b2..d4b68e41 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_payable.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_handle_with_payable.snap @@ -14,16 +14,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -37,17 +31,41 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { if gstd::msg::value() > 0 && gstd::msg::size() == 0 { @@ -55,7 +73,18 @@ pub mod wasm { } let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_multiple_ctors.snap b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_multiple_ctors.snap index ce50aab3..f4a92be0 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_multiple_ctors.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_multiple_ctors.snap @@ -17,7 +17,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -25,11 +24,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -37,11 +31,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -56,29 +45,70 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_no_ctor.snap b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_no_ctor.snap index ac6680cb..b01deb79 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_no_ctor.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_no_ctor.snap @@ -14,16 +14,10 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __CreateParams {} - impl InvocationIo for __CreateParams { - const ROUTE: &'static [u8] = &[24u8, 67u8, 114u8, 101u8, 97u8, 116u8, 101u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -37,22 +31,57 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__CreateParams::decode_params(input) { - let program = MyProgram::create(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (): () = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::create(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) + } } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_single_ctor.snap b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_single_ctor.snap index 679e47e9..04f75ec3 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_init_for_single_ctor.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_init_for_single_ctor.snap @@ -14,7 +14,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -22,11 +21,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -40,24 +34,59 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await; - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await; + unsafe { + PROGRAM = Some(program); + } + }); + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gprogram__generates_init_with_unwrap_result.snap b/rs/macros/core/tests/snapshots/gprogram__generates_init_with_unwrap_result.snap index 0cbda700..e9b9dc24 100644 --- a/rs/macros/core/tests/snapshots/gprogram__generates_init_with_unwrap_result.snap +++ b/rs/macros/core/tests/snapshots/gprogram__generates_init_with_unwrap_result.snap @@ -19,7 +19,6 @@ impl sails_rs::meta::ProgramMeta for MyProgram { } mod meta_in_program { use super::*; - use sails_rs::gstd::InvocationIo; #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -27,11 +26,6 @@ mod meta_in_program { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __NewParams { - const ROUTE: &'static [u8] = &[12u8, 78u8, 101u8, 119u8]; - type Params = Self; - const ASYNC: bool = true; - } #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] @@ -39,11 +33,6 @@ mod meta_in_program { pub(super) p2: String, pub(super) p1: u32, } - impl InvocationIo for __New2Params { - const ROUTE: &'static [u8] = &[16u8, 78u8, 101u8, 119u8, 50u8]; - type Params = Self; - const ASYNC: bool = false; - } #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum ConstructorsMeta { @@ -58,29 +47,70 @@ pub mod wasm { static mut PROGRAM: Option = None; #[unsafe(no_mangle)] extern "C" fn init() { - use gstd::InvocationIo; let mut input: &[u8] = &gstd::msg::load_bytes().expect("Failed to read input"); - if let Ok(request) = meta_in_program::__NewParams::decode_params(input) { - gstd::message_loop(async move { - let program = MyProgram::new(request.p1, request.p2).await.unwrap(); - unsafe { - PROGRAM = Some(program); + if let Ok(header) = ::decode( + &mut input, + ) { + if header.interface_id() != sails_rs::meta::InterfaceId::zero() { + sails_rs::gstd::unknown_input_panic( + "Non zero ctor interface_id", + header.to_bytes().as_slice(), + ); + } + match header.entry_id() { + 0u16 => { + let (p1, p2): (u32, String) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + gstd::message_loop(async move { + let program = MyProgram::new(p1, p2).await.unwrap(); + unsafe { + PROGRAM = Some(program); + } + }); + } + 1u16 => { + let (p2, p1): (String, u32) = sails_rs::Decode::decode(&mut input) + .unwrap_or_else(|_| sails_rs::gstd::unknown_input_panic( + "Unknown request", + input, + )); + let program = MyProgram::new2(p2, p1).unwrap(); + unsafe { + PROGRAM = Some(program); + } + } + _ => { + sails_rs::gstd::unknown_input_panic( + "Unexpected ctor entry_id", + input, + ) } - }); - } else if let Ok(request) = meta_in_program::__New2Params::decode_params(input) { - let program = MyProgram::new2(request.p2, request.p1).unwrap(); - unsafe { - PROGRAM = Some(program); } - } else { - gstd::unknown_input_panic("Unexpected ctor", input) - }; + } } + const SERVICES_COUNT: usize = 0usize; + const INTERFACE_IDS: &'static [(sails_rs::meta::InterfaceId, u8)] = &sails_rs::meta::interface_ids::< + SERVICES_COUNT, + >(&[]); #[unsafe(no_mangle)] extern "C" fn handle() { let mut input = gstd::msg::load_bytes().expect("Failed to read input"); let program_ref = unsafe { PROGRAM.as_mut() }.expect("Program not initialized"); - { gstd::unknown_input_panic("Unexpected service", &input) }; + if let Ok(header) = ::decode( + &mut input.as_slice(), + ) { + let header_len = header.hlen().inner() as usize; + let (interface_id, route_id, entry_id) = header + .try_match_interfaces(INTERFACE_IDS) + .expect("Failed to find matching service") + .into_inner(); + match route_id { + _ => gstd::unknown_input_panic("Unknown route_id", &[route_id]), + } + } } #[unsafe(no_mangle)] extern "C" fn handle_reply() { diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_allow_attrs.snap b/rs/macros/core/tests/snapshots/gservice__works_with_allow_attrs.snap index 69ae925c..890cb5af 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_allow_attrs.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_allow_attrs.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -49,135 +55,138 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_basics.snap b/rs/macros/core/tests/snapshots/gservice__works_with_basics.snap index f8d0d947..32d34198 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_basics.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_basics.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -39,142 +45,145 @@ impl core::ops::DerefMut for SomeServiceExposure { } impl SomeServiceExposure { #[export] - pub async fn do_this(&mut self, p1: u32, p2: String) -> u32 { - p1 + pub async fn do_this(&mut self, p1: u32, p2: String) -> String { + format!("{p1}: ") + &p2 } #[export] pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> String)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { - DoThis(__DoThisParams, u32), + DoThis(__DoThisParams, String), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_crate_path.snap b/rs/macros/core/tests/snapshots/gservice__works_with_crate_path.snap index 6d986604..20de8c74 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_crate_path.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_crate_path.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rename::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rename::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -46,140 +52,138 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rename::gstd::services::{Exposure, Service}; + use sails_rename::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rename::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rename::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rename::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rename::gstd::InvocationIo; - use sails_rename::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rename::gstd::services::{Exposure, Service}; + use sails_rename::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rename::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rename::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rename::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rename::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [( - &'static str, - sails_rename::meta::AnyServiceMetaFn, - )] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rename::meta::InterfaceId = { - let mut final_hash = sails_rename::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rename::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update( - &::HASH, - ); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rename::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rename::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rename::{Decode, TypeInfo}; - use sails_rename::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rename::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rename::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rename::meta::InterfaceId = { + let mut final_hash = sails_rename::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rename::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rename::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rename::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rename::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rename::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rename::Decode, sails_rename::TypeInfo)] #[codec(crate = sails_rename::scale_codec)] #[scale_info(crate = sails_rename::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rename::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rename::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rename::TypeInfo)] #[scale_info(crate = sails_rename::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_docs.snap b/rs/macros/core/tests/snapshots/gservice__works_with_docs.snap index eb60300f..3d450758 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_docs.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_docs.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -49,138 +55,141 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(request.p1, request.p2).await; - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { /// `DoThis` command /// Second line DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { /// `This` query This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_events.snap b/rs/macros/core/tests/snapshots/gservice__works_with_events.snap index 0cd7eaba..4fc1a2df 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_events.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_events.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -50,50 +56,75 @@ impl SomeServiceExposure { pub fn this(&self) -> bool { true } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(); - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: SomeEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -102,78 +133,62 @@ impl SomeServiceExposure { } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash.update(&sails_rs::hash_fn!(query This() -> bool)); + final_hash = final_hash + .update( + &::HASH, + ); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams {} - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = SomeEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_export.snap b/rs/macros/core/tests/snapshots/gservice__works_with_export.snap index 0aa86612..b7045e0b 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_export.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_export.snap @@ -3,29 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoSomethingParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -52,144 +56,142 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoSomethingParams::decode_params( - input, - ) { - let result = self.do_this(request.p1, request.p2).await.unwrap(); - let value = 0u128; - if !some_service_meta::__DoSomethingParams::is_empty_tuple::< - (u32, String), - >() { - some_service_meta::__DoSomethingParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoSomethingParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(request.p1, request.p2).await.unwrap(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<(u32, String)>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoSomething".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<(u32, String) as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update( + &sails_rs::hash_fn!( + command DoSomething(u32, String) -> (u32, String) + ), + ); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoSomethingParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoSomethingParams { - const ROUTE: &'static [u8] = &[ - 44u8, 68u8, 111u8, 83u8, 111u8, 109u8, 101u8, 116u8, 104u8, 105u8, 110u8, - 103u8, - ]; + impl sails_rs::gstd::InvocationIo for __DoSomethingParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoSomething(__DoSomethingParams, (u32, String)), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_extends.snap b/rs/macros/core/tests/snapshots/gservice__works_with_extends.snap index 3a01d221..0be094e7 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_extends.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_extends.snap @@ -3,34 +3,44 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -63,128 +73,149 @@ impl SomeServiceExposure { pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(); - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if base_services.0.expose(self.route).try_handle(input, result_handler).is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID { - return Some(()); - } - if base_services.1.expose(self.route).try_handle(input, result_handler).is_some() - { - return Some(()); + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services.0, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); + } + if sails_rs::gstd::services::Service::expose(base_services.1, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); + } + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); - if base_services - .0 - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID { - return Some(()); - } - if base_services - .1 - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() - { - return Some(()); + match entry_id { + _ => None, + } + } else { + let base_services: (ExtendedService1, ExtendedService2) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services.0, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + if sails_rs::gstd::services::Service::expose(base_services.1, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ - ("ExtendedService1", sails_rs::meta::AnyServiceMeta::new::), - ("ExtendedService2", sails_rs::meta::AnyServiceMeta::new::), - ]; - const ASYNC: bool = ::ASYNC - || ::ASYNC; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::INTERFACE_ID.0); - final_hash = final_hash - .update(&::INTERFACE_ID.0); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[ + sails_rs::meta::BaseServiceMeta::new::< + super::ExtendedService1, + >("ExtendedService1"), + sails_rs::meta::BaseServiceMeta::new::< + super::ExtendedService2, + >("ExtendedService2"), + ]; + const ASYNC: bool = ::ASYNC + || ::ASYNC; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_extends_and_lifetimes.snap b/rs/macros/core/tests/snapshots/gservice__works_with_extends_and_lifetimes.snap index 8d409dc2..d8c2cef8 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_extends_and_lifetimes.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_extends_and_lifetimes.snap @@ -3,36 +3,39 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct ExtendedLifetimeExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for ExtendedLifetimeExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = extended_lifetime_meta::__ExtendedNameParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = extended_lifetime_meta::__NameParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Some(is_async) = <::Exposure as Exposure>::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + _ => None, + } + } else { + if let Some(is_async) = <::Exposure as sails_rs::gstd::services::Exposure>::check_asyncness( + interface_id, + entry_id, + ) { + return Some(is_async); + } + None } - None } } impl core::ops::Deref for ExtendedLifetimeExposure { @@ -63,149 +66,155 @@ impl<'a> ExtendedLifetimeExposure> { pub fn name(&self) -> String { "extended".to_string() } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = extended_lifetime_meta::__ExtendedNameParams::decode_params( - input, - ) { - let result = self.extended_name(); - let value = 0u128; - if !extended_lifetime_meta::__ExtendedNameParams::is_empty_tuple::< - String, - >() { - extended_lifetime_meta::__ExtendedNameParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: extended_lifetime_meta::__ExtendedNameParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.extended_name(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: extended_lifetime_meta::__NameParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.name(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); - } - if let Ok(request) = extended_lifetime_meta::__NameParams::decode_params(input) { - let result = self.name(); - let value = 0u128; - if !extended_lifetime_meta::__NameParams::is_empty_tuple::() { - extended_lifetime_meta::__NameParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + } else { + let base_services: (base::BaseLifetime<'a>) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services, self.route_idx) + .try_handle(interface_id, entry_id, input, result_handler) + .is_some() + { + return Some(()); } - return Some(()); - } - let base_services: (base::BaseLifetime<'a>) = self.inner.into(); - if base_services.expose(self.route).try_handle(input, result_handler).is_some() { - return Some(()); + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - let base_services: (base::BaseLifetime<'a>) = self.inner.into(); - if base_services - .expose(self.route) - .try_handle_async(input, result_handler) - .await - .is_some() + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID { - return Some(()); + match entry_id { + _ => None, + } + } else { + let base_services: (base::BaseLifetime<'a>) = self.inner.into(); + if sails_rs::gstd::services::Service::expose(base_services, self.route_idx) + .try_handle_async(interface_id, entry_id, input, result_handler) + .await + .is_some() + { + return Some(()); + } + None } - None } } impl<'a> sails_rs::gstd::services::Service for ExtendedLifetime<'a> { type Exposure = ExtendedLifetimeExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a> sails_rs::meta::ServiceMeta for ExtendedLifetime<'a> { - type CommandsMeta = extended_lifetime_meta::CommandsMeta; - type QueriesMeta = extended_lifetime_meta::QueriesMeta; - type EventsMeta = extended_lifetime_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[ - ("BaseLifetime", sails_rs::meta::AnyServiceMeta::new::), - ]; - const ASYNC: bool = ::ASYNC; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("ExtendedName".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("Name".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update( - &::INTERFACE_ID.0, - ); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod extended_lifetime_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a> sails_rs::meta::ServiceMeta for super::ExtendedLifetime<'a> { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[ + sails_rs::meta::BaseServiceMeta::new::< + super::base::BaseLifetime, + >("BaseLifetime"), + ]; + const ASYNC: bool = ::ASYNC; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query ExtendedName() -> String)); + final_hash = final_hash.update(&sails_rs::hash_fn!(query Name() -> String)); + final_hash = final_hash + .update( + &::INTERFACE_ID + .0, + ); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ExtendedNameParams {} - impl InvocationIo for __ExtendedNameParams { - const ROUTE: &'static [u8] = &[ - 48u8, 69u8, 120u8, 116u8, 101u8, 110u8, 100u8, 101u8, 100u8, 78u8, 97u8, - 109u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __ExtendedNameParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __NameParams {} - impl InvocationIo for __NameParams { - const ROUTE: &'static [u8] = &[16u8, 78u8, 97u8, 109u8, 101u8]; + impl sails_rs::gstd::InvocationIo for __NameParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { ExtendedName(__ExtendedNameParams, String), Name(__NameParams, String), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_events.snap b/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_events.snap index 3808d401..97ca34f3 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_events.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_events.snap @@ -3,26 +3,32 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct MyGenericEventsServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for MyGenericEventsServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = my_generic_events_service_meta::__DoThisParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -48,40 +54,65 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = my_generic_events_service_meta::__DoThisParams::decode_params( - input, - ) { - let result = self.do_this(); - let value = 0u128; - if !my_generic_events_service_meta::__DoThisParams::is_empty_tuple::() { - my_generic_events_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: my_generic_events_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: MyEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -93,61 +124,51 @@ where T: Clone, { type Exposure = MyGenericEventsServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a, T> sails_rs::meta::ServiceMeta for MyGenericEventsService<'a, T> -where - T: Clone, -{ - type CommandsMeta = my_generic_events_service_meta::CommandsMeta; - type QueriesMeta = my_generic_events_service_meta::QueriesMeta; - type EventsMeta = my_generic_events_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod my_generic_events_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a, T> sails_rs::meta::ServiceMeta for super::MyGenericEventsService<'a, T> + where + T: Clone, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update(&::HASH); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = MyEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_generics.snap b/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_generics.snap index 1ae89f50..f20c1747 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_generics.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_lifetimes_and_generics.snap @@ -3,24 +3,32 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -43,38 +51,69 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let result = self.do_this(); - let value = 0u128; - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } } impl<'a, 'b, T, U> sails_rs::gstd::services::Service for SomeService<'a, 'b, T, U> @@ -83,60 +122,50 @@ where U: Iterator, { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl<'a, 'b, T, U> sails_rs::meta::ServiceMeta for SomeService<'a, 'b, T, U> -where - T: Clone, - U: Iterator, -{ - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl<'a, 'b, T, U> sails_rs::meta::ServiceMeta for super::SomeService<'a, 'b, T, U> + where + T: Clone, + U: Iterator, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_methods_with_lifetimes.snap b/rs/macros/core/tests/snapshots/gservice__works_with_methods_with_lifetimes.snap index ab62fa3b..5f55ecc8 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_methods_with_lifetimes.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_methods_with_lifetimes.snap @@ -3,46 +3,36 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct ReferenceServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for ReferenceServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = reference_service_meta::__AddByteParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__BakedParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__FirstByteParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__IncrParams::check_asyncness( - input, - ) { - return Some(is_async); - } - if let Ok(is_async) = reference_service_meta::__LastByteParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + 1u16 => Some(false), + 2u16 => Some(false), + 3u16 => Some(true), + 4u16 => Some(true), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for ReferenceServiceExposure { @@ -83,257 +73,223 @@ impl ReferenceServiceExposure { pub async fn last_byte<'a>(&self) -> Option<&'a u8> { unsafe { BYTES.last() } } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = reference_service_meta::__AddByteParams::decode_params( - input, - ) { - let result = self.add_byte(request.byte); - let value = 0u128; - if !reference_service_meta::__AddByteParams::is_empty_tuple::< - &'static [u8], - >() { - reference_service_meta::__AddByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__BakedParams::decode_params( - input, - ) { - let result = self.baked(); - let value = 0u128; - if !reference_service_meta::__BakedParams::is_empty_tuple::<&'static str>() { - reference_service_meta::__BakedParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__IncrParams::decode_params(input) { - let result = self.incr(); - let value = 0u128; - if !reference_service_meta::__IncrParams::is_empty_tuple::< - &'static ReferenceCount, - >() { - reference_service_meta::__IncrParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: reference_service_meta::__AddByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.add_byte(request.byte); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static [u8]>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 1u16 => { + let request: reference_service_meta::__IncrParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.incr(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static ReferenceCount>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 2u16 => { + let request: reference_service_meta::__BakedParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.baked(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::<&'static str>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = reference_service_meta::__FirstByteParams::decode_params( - input, - ) { - let result = self.first_byte().await; - let value = 0u128; - if !reference_service_meta::__FirstByteParams::is_empty_tuple::< - Option<&'static u8>, - >() { - reference_service_meta::__FirstByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); - } - return Some(()); - } - if let Ok(request) = reference_service_meta::__LastByteParams::decode_params( - input, - ) { - let result = self.last_byte().await; - let value = 0u128; - if !reference_service_meta::__LastByteParams::is_empty_tuple::< - Option<&'static u8>, - >() { - reference_service_meta::__LastByteParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 3u16 => { + let request: reference_service_meta::__FirstByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.first_byte().await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + 4u16 => { + let request: reference_service_meta::__LastByteParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.last_byte().await; + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::>() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for ReferenceService { type Exposure = ReferenceServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for ReferenceService { - type CommandsMeta = reference_service_meta::CommandsMeta; - type QueriesMeta = reference_service_meta::QueriesMeta; - type EventsMeta = reference_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("AddByte".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static [u8] as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("Incr".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static ReferenceCount as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("Baked".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update( - &<&'static str as sails_rs::sails_reflect_hash::ReflectHash>::HASH, - ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("FirstByte".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash +mod reference_service_meta { + use super::*; + impl sails_rs::meta::ServiceMeta for super::ReferenceService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command AddByte(u8) -> & 'static [u8])); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command Incr() -> & 'static ReferenceCount)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query Baked() -> & 'static str)); + final_hash = final_hash .update( - & as sails_rs::sails_reflect_hash::ReflectHash>::HASH, + &sails_rs::hash_fn!(query FirstByte() -> Option < & 'static u8 >), ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("LastByte".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash + final_hash = final_hash .update( - & as sails_rs::sails_reflect_hash::ReflectHash>::HASH, + &sails_rs::hash_fn!(query LastByte() -> Option < & 'static u8 >), ); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} -mod reference_service_meta { - use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __AddByteParams { pub(super) byte: u8, } - impl InvocationIo for __AddByteParams { - const ROUTE: &'static [u8] = &[ - 28u8, 65u8, 100u8, 100u8, 66u8, 121u8, 116u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __AddByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __BakedParams {} - impl InvocationIo for __BakedParams { - const ROUTE: &'static [u8] = &[20u8, 66u8, 97u8, 107u8, 101u8, 100u8]; + pub struct __IncrParams {} + impl sails_rs::gstd::InvocationIo for __IncrParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __FirstByteParams {} - impl InvocationIo for __FirstByteParams { - const ROUTE: &'static [u8] = &[ - 36u8, 70u8, 105u8, 114u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8, - ]; + pub struct __BakedParams {} + impl sails_rs::gstd::InvocationIo for __BakedParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 2u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] - pub struct __IncrParams {} - impl InvocationIo for __IncrParams { - const ROUTE: &'static [u8] = &[16u8, 73u8, 110u8, 99u8, 114u8]; + pub struct __FirstByteParams {} + impl sails_rs::gstd::InvocationIo for __FirstByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 3u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __LastByteParams {} - impl InvocationIo for __LastByteParams { - const ROUTE: &'static [u8] = &[ - 32u8, 76u8, 97u8, 115u8, 116u8, 66u8, 121u8, 116u8, 101u8, - ]; + impl sails_rs::gstd::InvocationIo for __LastByteParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 4u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { AddByte(__AddByteParams, &'static [u8]), Incr(__IncrParams, &'static ReferenceCount), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { Baked(__BakedParams, &'static str), FirstByte(__FirstByteParams, Option<&'static u8>), LastByte(__LastByteParams, Option<&'static u8>), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_reply_with_value.snap b/rs/macros/core/tests/snapshots/gservice__works_with_reply_with_value.snap index 8dac538f..f23fea8f 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_reply_with_value.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_reply_with_value.snap @@ -3,27 +3,33 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct SomeServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for SomeServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = some_service_meta::__DoThisParams::check_asyncness(input) { - return Some(is_async); - } - if let Ok(is_async) = some_service_meta::__ThisParams::check_asyncness(input) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(true), + 1u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl core::ops::Deref for SomeServiceExposure { @@ -46,138 +52,141 @@ impl SomeServiceExposure { pub fn this(&self, p1: bool) -> bool { p1 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__ThisParams::decode_params(input) { - let result = self.this(request.p1); - let value = 0u128; - if !some_service_meta::__ThisParams::is_empty_tuple::() { - some_service_meta::__ThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 1u16 => { + let request: some_service_meta::__ThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.this(request.p1); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = some_service_meta::__DoThisParams::decode_params(input) { - let command_reply: CommandReply = self - .do_this(request.p1, request.p2) - .await - .into(); - let (result, value) = command_reply.to_tuple(); - if !some_service_meta::__DoThisParams::is_empty_tuple::() { - some_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == ::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: some_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let command_reply: CommandReply = self + .do_this(request.p1, request.p2) + .await + .into(); + let (result, value) = command_reply.to_tuple(); + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } } impl sails_rs::gstd::services::Service for SomeService { type Exposure = SomeServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for SomeService { - type CommandsMeta = some_service_meta::CommandsMeta; - type QueriesMeta = some_service_meta::QueriesMeta; - type EventsMeta = some_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = true; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("query".as_bytes()); - fn_hash = fn_hash.update("This".as_bytes()); - fn_hash = fn_hash - .update(&::HASH); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod some_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::SomeService { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = true; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash + .update(&sails_rs::hash_fn!(command DoThis(u32, String) -> u32)); + final_hash = final_hash + .update(&sails_rs::hash_fn!(query This(bool) -> bool)); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams { pub(super) p1: u32, pub(super) p2: String, } - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = true; } - #[derive(Decode, TypeInfo)] + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __ThisParams { pub(super) p1: bool, } - impl InvocationIo for __ThisParams { - const ROUTE: &'static [u8] = &[16u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __ThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 1u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta { This(__ThisParams, bool), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = NoEvents; diff --git a/rs/macros/core/tests/snapshots/gservice__works_with_special_lifetimes_and_events.snap b/rs/macros/core/tests/snapshots/gservice__works_with_special_lifetimes_and_events.snap index d35d6545..6799486e 100644 --- a/rs/macros/core/tests/snapshots/gservice__works_with_special_lifetimes_and_events.snap +++ b/rs/macros/core/tests/snapshots/gservice__works_with_special_lifetimes_and_events.snap @@ -3,26 +3,32 @@ source: rs/macros/core/tests/gservice.rs expression: result --- pub struct MyGenericEventsServiceExposure { - route: &'static [u8], + route_idx: u8, inner: T, } impl sails_rs::gstd::services::Exposure for MyGenericEventsServiceExposure { - fn route(&self) -> &'static [u8] { - self.route + fn interface_id() -> sails_rs::meta::InterfaceId { + T::INTERFACE_ID } - fn check_asyncness(input: &[u8]) -> Option { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; + fn route_idx(&self) -> u8 { + self.route_idx + } + fn check_asyncness( + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + ) -> Option { if !T::ASYNC { return Some(false); } - if let Ok(is_async) = my_generic_events_service_meta::__DoThisParams::check_asyncness( - input, - ) { - return Some(is_async); + if interface_id == T::INTERFACE_ID { + match entry_id { + 0u16 => Some(false), + _ => None, + } + } else { + None } - None } } impl sails_rs::gstd::services::ExposureWithEvents @@ -48,40 +54,67 @@ where pub fn do_this(&mut self) -> u32 { 42 } - pub fn check_asyncness(&self, input: &[u8]) -> Option { - ::check_asyncness(input) - } pub fn try_handle( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - if let Ok(request) = my_generic_events_service_meta::__DoThisParams::decode_params( - input, - ) { - let result = self.do_this(); - let value = 0u128; - if !my_generic_events_service_meta::__DoThisParams::is_empty_tuple::() { - my_generic_events_service_meta::__DoThisParams::with_optimized_encode( - &result, - self.route().as_ref(), - |encoded_result| result_handler(encoded_result, value), - ); + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + 0u16 => { + let request: my_generic_events_service_meta::__DoThisParams = sails_rs::scale_codec::Decode::decode( + &mut input, + ) + .expect("Failed to decode params"); + let result = self.do_this(); + let value = 0u128; + if !sails_rs::gstd::is_empty_tuple::() { + ::with_optimized_encode( + &result, + self.route_idx, + |encoded_result| result_handler(encoded_result, value), + ); + } + return Some(()); + } + _ => None, } - return Some(()); + } else { + None } - None } pub async fn try_handle_async( mut self, - input: &[u8], + interface_id: sails_rs::meta::InterfaceId, + entry_id: u16, + mut input: &[u8], result_handler: fn(&[u8], u128), ) -> Option<()> { - use sails_rs::gstd::InvocationIo; - use sails_rs::gstd::services::{Service, Exposure}; - None + use sails_rs::gstd::services::{Exposure, Service}; + use sails_rs::gstd::{InvocationIo, CommandReply}; + if interface_id + == as sails_rs::meta::ServiceMeta>::INTERFACE_ID + { + match entry_id { + _ => None, + } + } else { + None + } } pub fn emit_event(&self, event: MyEvents) -> sails_rs::errors::Result<()> { use sails_rs::gstd::services::ExposureWithEvents; @@ -93,61 +126,51 @@ where T: Clone, { type Exposure = MyGenericEventsServiceExposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure { + fn expose(self, route_idx: u8) -> Self::Exposure { Self::Exposure { - route, + route_idx, inner: self, } } } -impl sails_rs::meta::ServiceMeta for MyGenericEventsService<'_, '_, T> -where - T: Clone, -{ - type CommandsMeta = my_generic_events_service_meta::CommandsMeta; - type QueriesMeta = my_generic_events_service_meta::QueriesMeta; - type EventsMeta = my_generic_events_service_meta::EventsMeta; - const BASE_SERVICES: &'static [(&'static str, sails_rs::meta::AnyServiceMetaFn)] = &[]; - const ASYNC: bool = false; - const INTERFACE_ID: sails_rs::meta::InterfaceId = { - let mut final_hash = sails_rs::keccak_const::Keccak256::new(); - { - let mut fn_hash = sails_rs::keccak_const::Keccak256::new(); - fn_hash = fn_hash.update("command".as_bytes()); - fn_hash = fn_hash.update("DoThis".as_bytes()); - fn_hash = fn_hash.update(b"res"); - fn_hash = fn_hash - .update(&::HASH); - final_hash = final_hash.update(&fn_hash.finalize()); - } - final_hash = final_hash - .update(&::HASH); - let hash = final_hash.finalize(); - sails_rs::meta::InterfaceId::from_bytes_32(hash) - }; -} mod my_generic_events_service_meta { use super::*; - use sails_rs::{Decode, TypeInfo}; - use sails_rs::gstd::InvocationIo; - #[derive(Decode, TypeInfo)] + impl sails_rs::meta::ServiceMeta for super::MyGenericEventsService<'_, '_, T> + where + T: Clone, + { + type CommandsMeta = CommandsMeta; + type QueriesMeta = QueriesMeta; + type EventsMeta = EventsMeta; + const BASE_SERVICES: &'static [sails_rs::meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: sails_rs::meta::InterfaceId = { + let mut final_hash = sails_rs::keccak_const::Keccak256::new(); + final_hash = final_hash.update(&sails_rs::hash_fn!(command DoThis() -> u32)); + final_hash = final_hash + .update(&::HASH); + let hash = final_hash.finalize(); + sails_rs::meta::InterfaceId::from_bytes_32(hash) + }; + } + #[derive(sails_rs::Decode, sails_rs::TypeInfo)] #[codec(crate = sails_rs::scale_codec)] #[scale_info(crate = sails_rs::scale_info)] pub struct __DoThisParams {} - impl InvocationIo for __DoThisParams { - const ROUTE: &'static [u8] = &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8]; + impl sails_rs::gstd::InvocationIo for __DoThisParams { + const INTERFACE_ID: sails_rs::meta::InterfaceId = ::INTERFACE_ID; + const ENTRY_ID: u16 = 0u16; type Params = Self; - const ASYNC: bool = false; } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum CommandsMeta { DoThis(__DoThisParams, u32), } - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum QueriesMeta {} - #[derive(TypeInfo)] + #[derive(sails_rs::TypeInfo)] #[scale_info(crate = sails_rs::scale_info)] pub enum NoEvents {} pub type EventsMeta = MyEvents; diff --git a/rs/macros/tests/gservice_tests.rs b/rs/macros/tests/gservice_tests.rs index 1e118cc9..aeea3c41 100644 --- a/rs/macros/tests/gservice_tests.rs +++ b/rs/macros/tests/gservice_tests.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "ethexe"))] -use sails_rs::gstd::services::{ExposureWithEvents, Service}; +use sails_rs::gstd::services::{Exposure, ExposureWithEvents, Service}; +use sails_rs::meta::{InterfaceId, SailsMessageHeader, ServiceMeta}; use sails_rs::{Decode, Encode}; mod gservice_with_basics; @@ -14,52 +15,45 @@ mod gservice_with_multiple_names; mod gservice_with_reply_with_value; mod gservice_with_trait_bounds; -/// Same service name is used for all the tests, -/// because under the hood exposure call context -/// stores service names in a static map, which is -/// accessed by different tests in a multi-threaded -/// environment. This leads to test's failure in case -/// race condition occurs. -const SERVICE_NAME: &str = "TestService"; -/// Service route which is same as `SERVICE_NAME.encode()` -const SERVICE_ROUTE: &[u8] = &[44, 84, 101, 115, 116, 83, 101, 114, 118, 105, 99, 101]; - #[tokio::test] async fn gservice_with_basics() { use gservice_with_basics::DoThisParams; use gservice_with_basics::SomeService; - const DO_THIS: &str = "DoThis"; - - let input = [ - DO_THIS.encode(), - DoThisParams { - p1: 42, - p2: "correct".into(), - } - .encode(), - ] - .concat(); + let header = SailsMessageHeader::v1(SomeService::INTERFACE_ID, 0, 1); - let exposure = SomeService.expose(SERVICE_ROUTE); + let input = DoThisParams { + p1: 42, + p2: "correct".into(), + } + .encode(); // Check asyncness of the service. - assert!(exposure.check_asyncness(&input).unwrap()); + assert!( + ::Exposure::check_asyncness( + header.interface_id(), + header.entry_id() + ) + .unwrap() + ); SomeService - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); + .expose(header.route_id()) + .try_handle_async( + header.interface_id(), + header.entry_id(), + &input, + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), SomeService::INTERFACE_ID); + assert_eq!(res_header.entry_id(), 0); + assert_eq!(res_header.route_id(), 1); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, "42: correct"); - - assert_eq!(output.len(), 0); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, "42: correct"); + assert_eq!(output.len(), 0); + }, + ) .await .unwrap(); } @@ -68,84 +62,88 @@ async fn gservice_with_basics() { fn gservice_with_extends() { use gservice_with_extends::{ base::{BASE_NAME_RESULT, Base}, - extended::{EXTENDED_NAME_RESULT, Extended, NAME_RESULT}, + extended::{EXTENDED_NAME_RESULT, Extended}, }; - const NAME_METHOD: &str = "Name"; - const BASE_NAME_METHOD: &str = "BaseName"; - const EXTENDED_NAME_METHOD: &str = "ExtendedName"; - - let extended_svc = Extended::new(Base).expose(SERVICE_ROUTE); + let extended_svc = Extended::new(Base).expose(1); + // Extended::extended_name + let header = SailsMessageHeader::v1(Extended::INTERFACE_ID, 0, 1); // Check asyncness of the service. assert!( - !extended_svc - .check_asyncness(&EXTENDED_NAME_METHOD.encode()) + !::Exposure::check_asyncness(header.interface_id(), header.entry_id()) .unwrap() ); extended_svc - .try_handle(&EXTENDED_NAME_METHOD.encode(), |mut output, _| { - let actual = output.to_vec(); - let expected = [ - SERVICE_ROUTE.to_vec(), - EXTENDED_NAME_METHOD.encode(), - EXTENDED_NAME_RESULT.encode(), - ] - .concat(); - - assert_eq!(actual, expected); - - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, EXTENDED_NAME_METHOD); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, EXTENDED_NAME_RESULT); - assert_eq!(output.len(), 0); - }) + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), Extended::INTERFACE_ID); + assert_eq!(res_header.entry_id(), 0); + assert_eq!(res_header.route_id(), 1); + + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, EXTENDED_NAME_RESULT); + assert_eq!(output.len(), 0); + }, + ) .unwrap(); - let extended_svc = Extended::new(Base).expose(SERVICE_ROUTE); + let extended_svc = Extended::new(Base).expose(1); + // Base::base_name + let header = SailsMessageHeader::v1(Base::INTERFACE_ID, 0, 1); // Check asyncness of the base service. assert!( - !extended_svc - .check_asyncness(&BASE_NAME_METHOD.encode()) + !::Exposure::check_asyncness(header.interface_id(), header.entry_id()) .unwrap() ); extended_svc - .try_handle(&BASE_NAME_METHOD.encode(), |mut output, _| { - // Even if base service method is called, the service route - // will be the same as extended service route. - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), Base::INTERFACE_ID); + assert_eq!(res_header.entry_id(), 0); + assert_eq!(res_header.route_id(), 1); - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, BASE_NAME_METHOD); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, BASE_NAME_RESULT); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, BASE_NAME_RESULT); + }, + ) .unwrap(); - let extended_svc = Extended::new(Base).expose(SERVICE_ROUTE); + let extended_svc = Extended::new(Base).expose(1); + // Base::name + let header = SailsMessageHeader::v1(Base::INTERFACE_ID, 1, 1); // Check asyncness of the base service. - assert!(!extended_svc.check_asyncness(&NAME_METHOD.encode()).unwrap()); + assert!( + !::Exposure::check_asyncness(header.interface_id(), header.entry_id()) + .unwrap() + ); extended_svc - .try_handle(&NAME_METHOD.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, NAME_METHOD); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, NAME_RESULT); - }) + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), Base::INTERFACE_ID); + assert_eq!(res_header.entry_id(), 1); + assert_eq!(res_header.route_id(), 1); + + // TODO: method not overrided + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, gservice_with_extends::base::NAME_RESULT); + }, + ) .unwrap(); } @@ -156,17 +154,19 @@ fn gservice_with_extends_renamed() { }; use sails_rs::meta::ServiceMeta; - let base_services = ::base_services().collect::>(); + let base_services = ::base_services() + .iter() + .collect::>(); assert_eq!(base_services.len(), 2); // You can create `ExtendedRenamed` with `Base` without renaming, as it's Rust type. - let _ = ExtendedRenamed::new((Base, OtherBase)).expose(SERVICE_ROUTE); + let _ = ExtendedRenamed::new((Base, OtherBase)).expose(1); - let (base_service_name, _) = base_services[0]; - assert_eq!(base_service_name, "RenamedBase"); + let base_service_meta = base_services[0]; + assert_eq!(base_service_meta.name, "RenamedBase"); - let (other_base_service_name, _) = base_services[1]; - assert_eq!(other_base_service_name, "Base"); + let other_base_service_meta = base_services[1]; + assert_eq!(other_base_service_meta.name, "Base"); } #[test] @@ -176,22 +176,27 @@ fn gservice_extends_pure() { extended_pure::ExtendedPure, }; - const NAME_METHOD: &str = "Name"; + let extended_svc = ExtendedPure::new(Base).expose(1); - let extended_svc = ExtendedPure::new(Base).expose(SERVICE_ROUTE); + // Base::name + let header = SailsMessageHeader::v1(Base::INTERFACE_ID, 1, 1); extended_svc - .try_handle(&NAME_METHOD.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), Base::INTERFACE_ID); + assert_eq!(res_header.entry_id(), 1); + assert_eq!(res_header.route_id(), 1); - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, NAME_METHOD); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, NAME_RESULT); - assert_eq!(output.len(), 0); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, NAME_RESULT); + assert_eq!(output.len(), 0); + }, + ) .unwrap(); } @@ -199,25 +204,33 @@ fn gservice_extends_pure() { fn gservice_with_lifecycles_and_generics() { use gservice_with_lifecycles_and_generics::SomeService; - const DO_THIS: &str = "DoThis"; - let mut iter = [42u32].into_iter(); let my_service = SomeService::<'_, '_, String, _>::new(&mut iter); - my_service - .expose(SERVICE_ROUTE) - .try_handle(&DO_THIS.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); + // SomeService::do_this + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); - let result = u32::decode(&mut output).unwrap(); - assert_eq!(result, 42); + my_service + .expose(1) + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ::INTERFACE_ID + ); + assert_eq!(res_header.entry_id(), 0); + assert_eq!(res_header.route_id(), 1); + + let result = u32::decode(&mut output).unwrap(); + assert_eq!(result, 42); - assert_eq!(output.len(), 0); - }) + assert_eq!(output.len(), 0); + }, + ) .unwrap(); } @@ -228,8 +241,8 @@ async fn gservice_panic_on_unexpected_input() { let input = [0xffu8; 16]; SomeService - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |_, _| { + .expose(1) + .try_handle_async(InterfaceId::zero(), 0, &input, |_, _| { panic!("Should not reach here"); }) .await @@ -260,8 +273,8 @@ fn gservice_panic_on_unexpected_input_double_encoded() { .encode(); SomeService - .expose(SERVICE_ROUTE) - .try_handle(&input, |_, _| { + .expose(1) + .try_handle(InterfaceId::zero(), 0, &input, |_, _| { panic!("Should not reach here"); }) .unwrap_or_else(|| sails_rs::gstd::unknown_input_panic("Unknown request", &input)); @@ -271,7 +284,7 @@ fn gservice_panic_on_unexpected_input_double_encoded() { fn gservice_with_events() { use gservice_with_events::{MyEvents, MyServiceWithEvents}; - let mut exposure = MyServiceWithEvents(0).expose(SERVICE_ROUTE); + let mut exposure = MyServiceWithEvents(0).expose(1); let mut emitter = exposure.emitter(); exposure.my_method(); @@ -282,27 +295,32 @@ fn gservice_with_events() { #[test] fn gservice_with_lifetimes_and_events() { - use gservice_with_lifetimes_and_events::{MyEvents, MyGenericEventsService}; - - const DO_THIS: &str = "DoThis"; + use gservice_with_lifetimes_and_events::{MyEvents, Service}; - let my_service = MyGenericEventsService::<'_, String>::default(); - let exposure = my_service.expose(SERVICE_ROUTE); + let my_service = Service::<'_, String>::default(); + let exposure = my_service.expose(1); + // Base::name + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); let mut emitter = exposure.emitter(); exposure - .try_handle(&DO_THIS.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); - - let result = u32::decode(&mut output).unwrap(); - assert_eq!(result, 42); + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ::INTERFACE_ID + ); + + let result = u32::decode(&mut output).unwrap(); + assert_eq!(result, 42); - assert_eq!(output.len(), 0); - }) + assert_eq!(output.len(), 0); + }, + ) .unwrap(); let events = emitter.take_events(); @@ -317,62 +335,79 @@ fn gservice_with_extends_and_lifetimes() { ExtendedWithLifetime, HIDDEN_NAME_RESULT, NAME_RESULT, }; - const NAME_METHOD: &str = "Name"; - const BASE_NAME_METHOD: &str = "BaseName"; - const EXTENDED_NAME_METHOD: &str = "ExtendedName"; - let int = 42u64; - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(SERVICE_ROUTE); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); - extended_svc - .try_handle(&EXTENDED_NAME_METHOD.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); + // ExtendedWithLifetime::extended_name + let header = SailsMessageHeader::v1(ExtendedWithLifetime::INTERFACE_ID, 0, 1); - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, EXTENDED_NAME_METHOD); + extended_svc + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ExtendedWithLifetime::INTERFACE_ID + ); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, EXTENDED_NAME_RESULT); - assert_eq!(output.len(), 0); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, EXTENDED_NAME_RESULT); + assert_eq!(output.len(), 0); + }, + ) .unwrap(); - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(SERVICE_ROUTE); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); + // BaseWithLifetime::base_name + let header = SailsMessageHeader::v1(BaseWithLifetime::INTERFACE_ID, 0, 1); extended_svc - .try_handle(&BASE_NAME_METHOD.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, BASE_NAME_METHOD); + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!(res_header.interface_id(), BaseWithLifetime::INTERFACE_ID); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, BASE_NAME_RESULT); - assert_eq!(output.len(), 0); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, BASE_NAME_RESULT); + assert_eq!(output.len(), 0); + }, + ) .unwrap(); - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(SERVICE_ROUTE); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); + // ExtendedWithLifetime::name + let header = SailsMessageHeader::v1(ExtendedWithLifetime::INTERFACE_ID, 1, 1); extended_svc - .try_handle(&NAME_METHOD.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, NAME_METHOD); + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ExtendedWithLifetime::INTERFACE_ID + ); + assert_eq!(res_header.entry_id(), 1); + assert_eq!(res_header.route_id(), 1); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, NAME_RESULT); - assert_eq!(output.len(), 0); - }) + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, NAME_RESULT); + assert_eq!(output.len(), 0); + }, + ) .unwrap(); - let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(SERVICE_ROUTE); + let extended_svc = ExtendedWithLifetime::new(BaseWithLifetime::new(&int)).expose(1); let base_svc: BaseWithLifetime = extended_svc.into(); - let base_exposure: BaseWithLifetimeExposure = base_svc.expose(SERVICE_ROUTE); + let base_exposure: BaseWithLifetimeExposure = base_svc.expose(1); let base_name = base_exposure.name(); assert_eq!(HIDDEN_NAME_RESULT, base_name) @@ -383,41 +418,43 @@ async fn gservice_with_reply_with_value() { use gservice_with_reply_with_value::MyDoThisParams; use gservice_with_reply_with_value::MyServiceWithReplyWithValue; - const DO_THIS: &str = "DoThis"; + let input = MyDoThisParams { + p1: 42, + p2: "correct".into(), + } + .encode(); - let input = [ - DO_THIS.encode(), - MyDoThisParams { - p1: 42, - p2: "correct".into(), - } - .encode(), - ] - .concat(); + // MyServiceWithReplyWithValue::do_this + let header = SailsMessageHeader::v1(MyServiceWithReplyWithValue::INTERFACE_ID, 1, 1); // No sync call with `DoThis` route. assert!( MyServiceWithReplyWithValue - .expose(SERVICE_ROUTE) - .try_handle(&input, |_, _| {}) + .expose(1) + .try_handle(header.interface_id(), header.entry_id(), &input, |_, _| {}) .is_none() ); MyServiceWithReplyWithValue - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |mut output, value| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); + .expose(1) + .try_handle_async( + header.interface_id(), + header.entry_id(), + &input, + |mut output, value| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + MyServiceWithReplyWithValue::INTERFACE_ID + ); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, "42: correct"); - assert_eq!(output.len(), 0); + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, "42: correct"); + assert_eq!(output.len(), 0); - assert_eq!(value, 100_000_000_000); - }) + assert_eq!(value, 100_000_000_000); + }, + ) .await .unwrap(); } @@ -427,33 +464,35 @@ async fn gservice_with_reply_with_value_with_impl_from() { use gservice_with_reply_with_value::MyDoThisParams; use gservice_with_reply_with_value::MyServiceWithReplyWithValue; - const DO_THAT: &str = "DoThat"; + let input = MyDoThisParams { + p1: 42, + p2: "correct".into(), + } + .encode(); - let input = [ - DO_THAT.encode(), - MyDoThisParams { - p1: 42, - p2: "correct".into(), - } - .encode(), - ] - .concat(); + // MyServiceWithReplyWithValue::do_that + let header = SailsMessageHeader::v1(MyServiceWithReplyWithValue::INTERFACE_ID, 0, 1); MyServiceWithReplyWithValue - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |mut output, value| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); + .expose(1) + .try_handle_async( + header.interface_id(), + header.entry_id(), + &input, + |mut output, value| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + MyServiceWithReplyWithValue::INTERFACE_ID + ); - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THAT); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, "42: correct"); - assert_eq!(output.len(), 0); + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, "42: correct"); + assert_eq!(output.len(), 0); - assert_eq!(value, 100_000_000_000); - }) + assert_eq!(value, 100_000_000_000); + }, + ) .await .unwrap(); } @@ -462,59 +501,72 @@ async fn gservice_with_reply_with_value_with_impl_from() { async fn gservice_with_trait_bounds() { use gservice_with_trait_bounds::MyServiceWithTraitBounds; - const DO_THIS: &str = "DoThis"; + // MyServiceWithTraitBounds::do_this + let header = SailsMessageHeader::v1( + ::INTERFACE_ID, + 0, + 1, + ); // No async call with `DoThis` route. assert!( MyServiceWithTraitBounds::::default() - .expose(SERVICE_ROUTE) - .try_handle_async(&DO_THIS.encode(), |_, _| {}) + .expose(1) + .try_handle_async(header.interface_id(), header.entry_id(), &[], |_, _| {}) .await .is_none() ); MyServiceWithTraitBounds::::default() - .expose(SERVICE_ROUTE) - .try_handle(&DO_THIS.encode(), |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); + .expose(1) + .try_handle( + header.interface_id(), + header.entry_id(), + &[], + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ::INTERFACE_ID, + ); + + let result = u32::decode(&mut output).unwrap(); + assert_eq!(result, 42); - let result = u32::decode(&mut output).unwrap(); - assert_eq!(result, 42); - - assert_eq!(output.len(), 0); - }) + assert_eq!(output.len(), 0); + }, + ) .unwrap(); } macro_rules! gservice_works { - ($service:expr) => { + ($service:ty) => { + let header = SailsMessageHeader::v1(<$service as ServiceMeta>::INTERFACE_ID, 0, 1); // `DO_THIS` is an async call - let input = [ - DO_THIS.encode(), - MyDoThisParams { - p1: 42, - p2: "correct".into(), - } - .encode(), - ] - .concat(); - $service - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); - - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, "42: correct"); - assert_eq!(output.len(), 0); - }) + let input = gservice_with_multiple_names::MyDoThisParams { + p1: 42, + p2: "correct".into(), + } + .encode(); + + <$service as Default>::default() + .expose(1) + .try_handle_async( + header.interface_id(), + header.entry_id(), + &input, + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + <$service as ServiceMeta>::INTERFACE_ID, + ); + + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, "42: correct"); + assert_eq!(output.len(), 0); + }, + ) .await .unwrap(); }; @@ -522,9 +574,6 @@ macro_rules! gservice_works { #[tokio::test] async fn gservice_with_multiple_names() { - use gservice_with_multiple_names::MyDoThisParams; - const DO_THIS: &str = "DoThis"; - gservice_works!(gservice_with_multiple_names::MyService); gservice_works!(gservice_with_multiple_names::MyOtherService); gservice_works!(gservice_with_multiple_names::yet_another_service::MyService); @@ -535,32 +584,33 @@ async fn gservice_with_export_unwrap_result() { use gservice_with_export_unwrap_result::MyDoThisParams; use gservice_with_export_unwrap_result::MyService; - const DO_THIS: &str = "DoThis"; + let header = SailsMessageHeader::v1(::INTERFACE_ID, 0, 1); - let input = [ - DO_THIS.encode(), - MyDoThisParams { - p1: 42, - p2: "correct".into(), - } - .encode(), - ] - .concat(); + let input = MyDoThisParams { + p1: 42, + p2: "correct".into(), + } + .encode(); MyService - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |mut output, _| { - let service_route = String::decode(&mut output).unwrap(); - assert_eq!(service_route, SERVICE_NAME); - - let func_name = String::decode(&mut output).unwrap(); - assert_eq!(func_name, DO_THIS); + .expose(1) + .try_handle_async( + header.interface_id(), + header.entry_id(), + &input, + |mut output, _| { + let res_header = SailsMessageHeader::decode(&mut output).unwrap(); + assert_eq!( + res_header.interface_id(), + ::INTERFACE_ID, + ); - let result = String::decode(&mut output).unwrap(); - assert_eq!(result, "42: correct"); + let result = String::decode(&mut output).unwrap(); + assert_eq!(result, "42: correct"); - assert_eq!(output.len(), 0); - }) + assert_eq!(output.len(), 0); + }, + ) .await .unwrap(); } @@ -570,13 +620,13 @@ async fn gservice_with_export_unwrap_result() { async fn gservice_with_export_unwrap_result_panic() { use gservice_with_export_unwrap_result::MyService; - const PARSE: &str = "Parse"; + let header = SailsMessageHeader::v1(::INTERFACE_ID, 1, 1); - let input = (PARSE, "not a number").encode(); + let input = "not a number".encode(); MyService - .expose(SERVICE_ROUTE) - .try_handle_async(&input, |_, _| { + .expose(1) + .try_handle_async(header.interface_id(), header.entry_id(), &input, |_, _| { unreachable!("Should not reach here"); }) .await diff --git a/rs/macros/tests/gservice_with_extends/mod.rs b/rs/macros/tests/gservice_with_extends/mod.rs index 6a84df25..df3ff604 100644 --- a/rs/macros/tests/gservice_with_extends/mod.rs +++ b/rs/macros/tests/gservice_with_extends/mod.rs @@ -14,12 +14,12 @@ pub(super) mod base { impl Base { #[export] pub fn base_name(&self) -> String { - "base-name".to_string() + BASE_NAME_RESULT.to_string() } #[export] pub fn name(&self) -> String { - "base".to_string() + NAME_RESULT.to_string() } } } @@ -44,12 +44,12 @@ pub(super) mod extended { impl Extended { #[export] pub fn extended_name(&self) -> String { - "extended-name".to_string() + EXTENDED_NAME_RESULT.to_string() } #[export] pub fn name(&self) -> String { - "extended".to_string() + NAME_RESULT.to_string() } } diff --git a/rs/macros/tests/gservice_with_lifecycles_and_generics/mod.rs b/rs/macros/tests/gservice_with_lifecycles_and_generics/mod.rs index 281ae2de..e671a58d 100644 --- a/rs/macros/tests/gservice_with_lifecycles_and_generics/mod.rs +++ b/rs/macros/tests/gservice_with_lifecycles_and_generics/mod.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; -pub(super) struct SomeService<'a, 'b, T, U> { +pub(super) struct SomeService<'a, 'b, T = String, U = core::option::IntoIter> { _t: PhantomData<&'a T>, u: &'b mut U, } diff --git a/rs/macros/tests/gservice_with_lifetimes_and_events/mod.rs b/rs/macros/tests/gservice_with_lifetimes_and_events/mod.rs index 343f6629..9e410717 100644 --- a/rs/macros/tests/gservice_with_lifetimes_and_events/mod.rs +++ b/rs/macros/tests/gservice_with_lifetimes_and_events/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; #[derive(Default)] -pub(super) struct MyGenericEventsService<'l, T> { +pub(super) struct Service<'l, T = String> { _t: Option, _a: PhantomData<&'l T>, } @@ -15,7 +15,7 @@ pub enum MyEvents { } #[service(events = MyEvents)] -impl MyGenericEventsService<'_, T> +impl Service<'_, T> where T: Clone, { diff --git a/rs/macros/tests/gservice_with_multiple_names/mod.rs b/rs/macros/tests/gservice_with_multiple_names/mod.rs index 7518457d..8e79774b 100644 --- a/rs/macros/tests/gservice_with_multiple_names/mod.rs +++ b/rs/macros/tests/gservice_with_multiple_names/mod.rs @@ -1,5 +1,6 @@ use sails_rs::prelude::*; +#[derive(Debug, Default)] pub(super) struct MyService; // Service @@ -23,6 +24,7 @@ pub(super) struct MyDoThisParams { pub(super) p2: String, } +#[derive(Debug, Default)] pub(super) struct MyOtherService; // Service with different name @@ -42,6 +44,8 @@ impl MyOtherService { pub mod yet_another_service { use super::*; + + #[derive(Debug, Default)] pub struct MyService; // Service with duplicate name in another module #[service] diff --git a/rs/macros/tests/gservice_with_trait_bounds/mod.rs b/rs/macros/tests/gservice_with_trait_bounds/mod.rs index fcdfb65f..b5a18eba 100644 --- a/rs/macros/tests/gservice_with_trait_bounds/mod.rs +++ b/rs/macros/tests/gservice_with_trait_bounds/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use sails_rs::prelude::*; #[derive(Default)] -pub(super) struct MyServiceWithTraitBounds<'a, T> { +pub(super) struct MyServiceWithTraitBounds<'a, T = u32> { _a: PhantomData<&'a T>, } diff --git a/rs/src/client/gclient_env.rs b/rs/src/client/gclient_env.rs index 33ba49ec..7071392f 100644 --- a/rs/src/client/gclient_env.rs +++ b/rs/src/client/gclient_env.rs @@ -88,7 +88,7 @@ impl GearEnv for GclientEnv { type MessageState = Pin), GclientError>>>>; } -impl PendingCall { +impl PendingCall { pub async fn send_one_way(&mut self) -> Result { let (payload, params) = self.take_encoded_args_and_params(); self.env @@ -112,12 +112,12 @@ impl PendingCall { query_calculate_reply(&self.env.api, self.destination, payload, params).await?; // Decode reply - T::decode_reply_with_prefix(self.route, reply_bytes) + T::decode_reply_with_header(self.route_idx, reply_bytes) .map_err(|err| gclient::Error::Codec(err).into()) } } -impl Future for PendingCall { +impl Future for PendingCall { type Output = Result::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -136,7 +136,7 @@ impl Future for PendingCall { .unwrap_or_else(|| panic!("{PENDING_CALL_INVALID_STATE}")); // Poll message future match ready!(message_future.poll(cx)) { - Ok((_, payload)) => match T::decode_reply_with_prefix(self.route, payload) { + Ok((_, payload)) => match T::decode_reply_with_header(self.route_idx, payload) { Ok(decoded) => Poll::Ready(Ok(decoded)), Err(err) => Poll::Ready(Err(gclient::Error::Codec(err).into())), }, @@ -145,7 +145,7 @@ impl Future for PendingCall { } } -impl Future for PendingCtor { +impl Future for PendingCtor { type Output = Result, ::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -157,7 +157,7 @@ impl Future for PendingCtor { .args .take() .unwrap_or_else(|| panic!("{PENDING_CTOR_INVALID_STATE}")); - let payload = T::encode_params(&args); + let payload = T::encode_params_with_header(0, &args); let create_program_future = create_program(self.env.api.clone(), self.code_id, salt, payload, params); diff --git a/rs/src/client/gstd_env.rs b/rs/src/client/gstd_env.rs index b4515e72..ed58f352 100644 --- a/rs/src/client/gstd_env.rs +++ b/rs/src/client/gstd_env.rs @@ -43,7 +43,7 @@ impl GstdParams { } } -impl PendingCall { +impl PendingCall { /// Set `redirect_on_exit` flag to `true`` /// /// This flag is used to redirect a message to a new program when the target program exits @@ -103,7 +103,7 @@ impl GstdEnv { } } -impl PendingCall { +impl PendingCall { pub fn send_one_way(&mut self) -> Result { let (payload, params) = self.take_encoded_args_and_params(); self.env.send_one_way(self.destination, payload, params) @@ -181,7 +181,7 @@ const _: () = { } } - impl Future for PendingCall { + impl Future for PendingCall { type Output = Result::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -190,7 +190,7 @@ const _: () = { .args .as_ref() .unwrap_or_else(|| panic!("{PENDING_CALL_INVALID_STATE}")); - let payload = T::encode_params_with_prefix(self.route, &args); + let payload = T::encode_params_with_header(self.route_idx, &args); let destination = self.destination; let params = self.params.get_or_insert_default(); // Send message @@ -211,8 +211,8 @@ const _: () = { match output { // ok reply Ok(payload) => { - let res = - T::decode_reply_with_prefix(self.route, payload).map_err(Error::Decode)?; + let res = T::decode_reply_with_header(self.route_idx, payload) + .map_err(Error::Decode)?; Poll::Ready(Ok(res)) } // reply with ProgramExited @@ -264,7 +264,7 @@ const _: () = { } } - impl Future for PendingCtor { + impl Future for PendingCtor { type Output = Result, ::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -277,7 +277,7 @@ const _: () = { .args .as_ref() .unwrap_or_else(|| panic!("{PENDING_CALL_INVALID_STATE}")); - let payload = T::encode_params(args); + let payload = T::encode_params_with_header(0, args); // Send message #[cfg(not(feature = "ethexe"))] let future = if let Some(gas_limit) = params.gas_limit { @@ -349,7 +349,7 @@ pin_project_lite::pin_project! { #[cfg(not(target_arch = "wasm32"))] const _: () = { - impl PendingCall + impl PendingCall where T::Reply: Encode + Decode, { @@ -365,7 +365,7 @@ const _: () = { PendingCall { env: GstdEnv, destination: ActorId::zero(), - route: "", + route_idx: 0, params: None, args: None, state: Some(future::ready(res.map(|v| v.encode()))), @@ -373,7 +373,7 @@ const _: () = { } } - impl, O> From for PendingCall + impl, O> From for PendingCall where O: Encode + Decode, { @@ -382,7 +382,7 @@ const _: () = { } } - impl Future for PendingCall { + impl Future for PendingCall { type Output = Result::Error>; fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { @@ -396,7 +396,7 @@ const _: () = { } } - impl Future for PendingCtor { + impl Future for PendingCtor { type Output = Result, ::Error>; fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { diff --git a/rs/src/client/gtest_env.rs b/rs/src/client/gtest_env.rs index 24f910f3..7a346546 100644 --- a/rs/src/client/gtest_env.rs +++ b/rs/src/client/gtest_env.rs @@ -274,7 +274,7 @@ impl GearEnv for GtestEnv { type MessageState = ReplyReceiver; } -impl PendingCall { +impl PendingCall { pub fn send_one_way(&mut self) -> Result { if self.state.is_some() { panic!("{PENDING_CALL_INVALID_STATE}"); @@ -298,12 +298,12 @@ impl PendingCall { let reply_bytes = self.env.query(self.destination, payload, params)?; // Decode reply - T::decode_reply_with_prefix(self.route, reply_bytes) + T::decode_reply_with_header(self.route_idx, reply_bytes) .map_err(|err| TestError::ScaleCodecError(err).into()) } } -impl Future for PendingCall { +impl Future for PendingCall { type Output = Result::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -330,7 +330,7 @@ impl Future for PendingCall { // Poll reply receiver match ready!(reply_receiver.poll(cx)) { Ok(res) => match res { - Ok(payload) => match T::decode_reply_with_prefix(self.route, payload) { + Ok(payload) => match T::decode_reply_with_header(self.route_idx, payload) { Ok(reply) => Poll::Ready(Ok(reply)), Err(err) => Poll::Ready(Err(TestError::ScaleCodecError(err).into())), }, @@ -341,7 +341,7 @@ impl Future for PendingCall { } } -impl PendingCtor { +impl PendingCtor { pub fn create_program(mut self) -> Result { if self.state.is_some() { panic!("{PENDING_CTOR_INVALID_STATE}"); @@ -351,7 +351,7 @@ impl PendingCtor { .args .take() .unwrap_or_else(|| panic!("{PENDING_CTOR_INVALID_STATE}")); - let payload = T::encode_params(&args); + let payload = T::encode_params_with_header(0, &args); let params = self.params.take().unwrap_or_default(); let salt = self.salt.take().unwrap_or_default(); let send_res = self @@ -372,7 +372,7 @@ impl PendingCtor { } } -impl Future for PendingCtor { +impl Future for PendingCtor { type Output = Result, ::Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -382,7 +382,7 @@ impl Future for PendingCtor { .args .take() .unwrap_or_else(|| panic!("{PENDING_CTOR_INVALID_STATE}")); - let payload = T::encode_params(&args); + let payload = T::encode_params_with_header(0, &args); let params = self.params.take().unwrap_or_default(); let salt = self.salt.take().unwrap_or_default(); let send_res = self diff --git a/rs/src/client/mod.rs b/rs/src/client/mod.rs index 359a1d59..47a2b061 100644 --- a/rs/src/client/mod.rs +++ b/rs/src/client/mod.rs @@ -1,3 +1,4 @@ +use crate::meta::SailsMessageHeader; use crate::prelude::*; use core::{ any::TypeId, @@ -7,6 +8,7 @@ use core::{ task::{Context, Poll}, }; use futures::Stream; +pub use sails_idl_meta::InterfaceId; #[cfg(feature = "gtest")] #[cfg(not(target_arch = "wasm32"))] @@ -50,8 +52,6 @@ pub trait Program: Sized { } } -pub type Route = &'static str; - #[derive(Debug, Clone)] pub struct Deployment { env: E, @@ -85,7 +85,7 @@ impl Deployment { } } - pub fn pending_ctor(self, args: T::Params) -> PendingCtor { + pub fn pending_ctor(self, args: T::Params) -> PendingCtor { PendingCtor::new(self.env, self.code_id, self.salt, args) } } @@ -128,25 +128,29 @@ impl Actor { self } - pub fn service(&self, route: Route) -> Service { - Service::new(self.env.clone(), self.id, route) + pub fn service(&self, route_idx: u8) -> Service { + Service::new(self.env.clone(), self.id, route_idx) } } +pub trait Identifiable { + const INTERFACE_ID: InterfaceId; +} + #[derive(Debug, Clone)] pub struct Service { env: E, actor_id: ActorId, - route: Route, + route_idx: u8, _phantom: PhantomData, } impl Service { - pub fn new(env: E, actor_id: ActorId, route: Route) -> Self { + pub fn new(env: E, actor_id: ActorId, route_idx: u8) -> Self { Service { env, actor_id, - route, + route_idx, _phantom: PhantomData, } } @@ -155,8 +159,15 @@ impl Service { self.actor_id } - pub fn route(&self) -> Route { - self.route + pub fn interface_id(&self) -> InterfaceId + where + S: Identifiable, + { + S::INTERFACE_ID + } + + pub fn route_idx(&self) -> u8 { + self.route_idx } pub fn with_actor_id(mut self, actor_id: ActorId) -> Self { @@ -164,12 +175,27 @@ impl Service { self } - pub fn pending_call(&self, args: T::Params) -> PendingCall { - PendingCall::new(self.env.clone(), self.actor_id, self.route, args) + pub fn pending_call(&self, args: T::Params) -> PendingCall { + PendingCall::new(self.env.clone(), self.actor_id, self.route_idx, args) } pub fn base_service(&self) -> Service { - Service::new(self.env.clone(), self.actor_id, self.route) + Service::new(self.env.clone(), self.actor_id, self.route_idx) + } + + pub fn decode_reply( + &self, + payload: impl AsRef<[u8]>, + ) -> Result { + T::decode_reply_with_header(self.route_idx, payload) + } + + #[cfg(not(target_arch = "wasm32"))] + pub fn decode_event( + &self, + payload: impl AsRef<[u8]>, + ) -> Result { + Ev::decode_event(self.route_idx, payload) } #[cfg(not(target_arch = "wasm32"))] @@ -177,7 +203,7 @@ impl Service { where S: ServiceWithEvents, { - ServiceListener::new(self.env.clone(), self.actor_id, self.route) + ServiceListener::new(self.env.clone(), self.actor_id, self.route_idx) } } @@ -190,17 +216,17 @@ pub trait ServiceWithEvents { pub struct ServiceListener { env: E, actor_id: ActorId, - route: Route, + route_idx: u8, _phantom: PhantomData, } #[cfg(not(target_arch = "wasm32"))] impl ServiceListener { - pub fn new(env: E, actor_id: ActorId, route: Route) -> Self { + pub fn new(env: E, actor_id: ActorId, route_idx: u8) -> Self { ServiceListener { env, actor_id, - route, + route_idx, _phantom: PhantomData, } } @@ -212,23 +238,25 @@ impl ServiceListener { E: Listener::Error>, { let self_id = self.actor_id; - let prefix = self.route; + let route_idx = self.route_idx; self.env .listen(move |(actor_id, payload)| { if actor_id != self_id { return None; } - D::decode_event(prefix, payload).ok().map(|e| (actor_id, e)) + D::decode_event(route_idx, payload) + .ok() + .map(|e| (actor_id, e)) }) .await } } pin_project_lite::pin_project! { - pub struct PendingCall { + pub struct PendingCall { env: E, destination: ActorId, - route: Route, + route_idx: u8, params: Option, args: Option, #[pin] @@ -236,12 +264,12 @@ pin_project_lite::pin_project! { } } -impl PendingCall { - pub fn new(env: E, destination: ActorId, route: Route, args: T::Params) -> Self { +impl PendingCall { + pub fn new(env: E, destination: ActorId, route_idx: u8, args: T::Params) -> Self { PendingCall { env, destination, - route, + route_idx, params: None, args: Some(args), state: None, @@ -258,20 +286,25 @@ impl PendingCall { self } + pub fn encode_call(mut self) -> Vec { + let (payload, _) = self.take_encoded_args_and_params(); + payload + } + #[inline] fn take_encoded_args_and_params(&mut self) -> (Vec, E::Params) { let args = self .args .take() .unwrap_or_else(|| panic!("{PENDING_CALL_INVALID_STATE}")); - let payload = T::encode_params_with_prefix(self.route, &args); + let payload = T::encode_params_with_header(self.route_idx, &args); let params = self.params.take().unwrap_or_default(); (payload, params) } } pin_project_lite::pin_project! { - pub struct PendingCtor { + pub struct PendingCtor { env: E, code_id: CodeId, params: Option, @@ -284,7 +317,7 @@ pin_project_lite::pin_project! { } } -impl PendingCtor { +impl PendingCtor { pub fn new(env: E, code_id: CodeId, salt: Vec, args: T::Params) -> Self { PendingCtor { env, @@ -304,75 +337,61 @@ impl PendingCtor { } } -pub trait CallCodec { - const ROUTE: Route; +pub trait ServiceCall: Identifiable { + const ENTRY_ID: u16; type Params: Encode; type Reply: Decode + 'static; - fn encode_params(value: &Self::Params) -> Vec { - let size = Encode::encoded_size(Self::ROUTE) + Encode::encoded_size(value); - let mut result = Vec::with_capacity(size); - Encode::encode_to(Self::ROUTE, &mut result); - Encode::encode_to(value, &mut result); - result - } - - fn encode_params_with_prefix(prefix: Route, value: &Self::Params) -> Vec { - let size = Encode::encoded_size(prefix) - + Encode::encoded_size(Self::ROUTE) - + Encode::encoded_size(value); - let mut result = Vec::with_capacity(size); - Encode::encode_to(prefix, &mut result); - Encode::encode_to(Self::ROUTE, &mut result); - Encode::encode_to(value, &mut result); + fn encode_params_with_header(route_idx: u8, value: &Self::Params) -> Vec { + let header = SailsMessageHeader::new( + crate::meta::Version::v1(), + crate::meta::HeaderLength::new(crate::meta::MINIMAL_HLEN).unwrap(), + Self::INTERFACE_ID, + route_idx, + Self::ENTRY_ID, + ); + let mut result = header.to_bytes(); + value.encode_to(&mut result); result } - fn decode_reply(payload: impl AsRef<[u8]>) -> Result { - let mut value = payload.as_ref(); - if Self::is_empty_tuple::() { - return Decode::decode(&mut value); - } - // Decode payload as `(String, Self::Reply)` - let route = String::decode(&mut value)?; - if route != Self::ROUTE { - return Err("Invalid reply prefix".into()); - } - Decode::decode(&mut value) - } - - fn decode_reply_with_prefix( - prefix: Route, + fn decode_reply_with_header( + route_idx: u8, payload: impl AsRef<[u8]>, ) -> Result { let mut value = payload.as_ref(); if Self::is_empty_tuple::() { return Decode::decode(&mut value); } - // Decode payload as `(String, String, Self::Reply)` - let route = String::decode(&mut value)?; - if route != prefix { - return Err("Invalid reply prefix".into()); + let header = SailsMessageHeader::decode(&mut value)?; + if header.interface_id() != Self::INTERFACE_ID { + return Err("Invalid reply interface_id".into()); } - let route = String::decode(&mut value)?; - if route != Self::ROUTE { - return Err("Invalid reply prefix".into()); + if header.route_id() != route_idx { + return Err("Invalid reply route_idx".into()); + } + if header.entry_id() != Self::ENTRY_ID { + return Err("Invalid reply entry_id".into()); } Decode::decode(&mut value) } fn with_optimized_encode( - prefix: Route, + route_idx: u8, value: &Self::Params, f: impl FnOnce(&[u8]) -> R, ) -> R { - let size = Encode::encoded_size(prefix) - + Encode::encoded_size(Self::ROUTE) - + Encode::encoded_size(value); + let header = SailsMessageHeader::new( + crate::meta::Version::v1(), + crate::meta::HeaderLength::new(crate::meta::MINIMAL_HLEN).unwrap(), + Self::INTERFACE_ID, + route_idx, + Self::ENTRY_ID, + ); + let size = (crate::meta::MINIMAL_HLEN as usize) + Encode::encoded_size(value); gcore::stack_buffer::with_byte_buffer(size, |buffer| { let mut buffer_writer = crate::utils::MaybeUninitBufferWriter::new(buffer); - Encode::encode_to(prefix, &mut buffer_writer); - Encode::encode_to(Self::ROUTE, &mut buffer_writer); + header.encode_to(&mut buffer_writer); Encode::encode_to(value, &mut buffer_writer); buffer_writer.with_buffer(f) }) @@ -408,7 +427,7 @@ macro_rules! params_struct_impl { )* } - impl PendingCtor { + impl PendingCtor { $( paste::paste! { $(#[$attr])* @@ -419,7 +438,7 @@ macro_rules! params_struct_impl { )* } - impl PendingCall { + impl PendingCall { $( paste::paste! { $(#[$attr])* @@ -450,7 +469,7 @@ macro_rules! params_for_pending_impl { )* } - impl PendingCtor { + impl PendingCtor { $( paste::paste! { $(#[$attr])* @@ -461,7 +480,7 @@ macro_rules! params_for_pending_impl { )* } - impl PendingCall { + impl PendingCall { $( paste::paste! { $(#[$attr])* @@ -477,23 +496,33 @@ macro_rules! params_for_pending_impl { #[macro_export] macro_rules! io_struct_impl { ( - $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty + $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty, $entry_id:expr, $interface_id:expr ) => { pub struct $name(()); impl $name { - pub fn encode_params($( $param: $ty, )* ) -> Vec { - <$name as CallCodec>::encode_params(&( $( $param, )* )) + /// Encodes the full call with the correct Sails header (Interface ID + Route Index + Entry ID). + pub fn encode_call(route_idx: u8, $( $param: $ty, )* ) -> Vec { + <$name as ServiceCall>::encode_params_with_header(route_idx, &( $( $param, )* )) } - pub fn encode_params_with_prefix(prefix: Route, $( $param: $ty, )* ) -> Vec { - <$name as CallCodec>::encode_params_with_prefix(prefix, &( $( $param, )* )) + /// Decodes the reply checking against the correct Sails header (Interface ID + Route Index + Entry ID). + pub fn decode_reply(route_idx: u8, payload: impl AsRef<[u8]>) -> Result<$reply, $crate::scale_codec::Error> { + <$name as ServiceCall>::decode_reply_with_header(route_idx, payload) } } - impl CallCodec for $name { - const ROUTE: &'static str = stringify!($name); + impl Identifiable for $name { + const INTERFACE_ID: InterfaceId = $interface_id; + } + impl ServiceCall for $name { + const ENTRY_ID: u16 = $entry_id; type Params = ( $( $ty, )* ); type Reply = $reply; } }; + ( + $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty, $entry_id:expr + ) => { + $crate::io_struct_impl!($name ( $( $param : $ty ),* ) -> $reply, $entry_id, $crate::meta::InterfaceId::zero()); + }; } #[allow(unused_macros)] @@ -530,69 +559,139 @@ pub trait Listener { ) -> Result + Unpin, Self::Error>; } -#[cfg(not(target_arch = "wasm32"))] -pub trait Event: Decode { - const EVENT_NAMES: &'static [Route]; +struct EventInput<'a> { + idx: u8, + payload: &'a [u8], + first: bool, +} + +impl<'a> parity_scale_codec::Input for EventInput<'a> { + fn remaining_len(&mut self) -> Result, parity_scale_codec::Error> { + Ok(Some(1 + self.payload.len())) + } + + fn read(&mut self, into: &mut [u8]) -> Result<(), parity_scale_codec::Error> { + if into.is_empty() { + return Ok(()); + } + let (head, tail) = into.split_at_mut(if self.first { 1 } else { 0 }); + if self.first { + head[0] = self.idx; + self.first = false; + } + if tail.is_empty() { + return Ok(()); + } + if tail.len() > self.payload.len() { + return Err("Not enough data to fill buffer".into()); + } + tail.copy_from_slice(&self.payload[..tail.len()]); + self.payload = &self.payload[tail.len()..]; + Ok(()) + } + + fn read_byte(&mut self) -> Result { + if self.first { + self.first = false; + Ok(self.idx) + } else { + let b = *self.payload.first().ok_or("Not enough data to read byte")?; + self.payload = &self.payload[1..]; + Ok(b) + } + } +} +#[cfg(not(target_arch = "wasm32"))] +pub trait Event: Decode + Identifiable { fn decode_event( - prefix: Route, + route_idx: u8, payload: impl AsRef<[u8]>, ) -> Result { let mut payload = payload.as_ref(); - let route = String::decode(&mut payload)?; - if route != prefix { - return Err("Invalid event prefix".into()); + + let header = SailsMessageHeader::decode(&mut payload)?; + if header.interface_id() != Self::INTERFACE_ID { + return Err("Invalid event interface_id".into()); } - let evt_name = String::decode(&mut payload)?; - for (idx, &name) in Self::EVENT_NAMES.iter().enumerate() { - if evt_name == name { - let idx = idx as u8; - let bytes = [&[idx], payload].concat(); - let mut event_bytes = &bytes[..]; - return Decode::decode(&mut event_bytes); - } + if header.route_id() != route_idx { + return Err("Invalid event route_idx".into()); + } + + let entry_id = header.entry_id(); + if entry_id > 255 { + return Err("Entry ID exceeds u8 limit for SCALE enum".into()); } - Err("Invalid event name".into()) + + // Reconstruct the standard SCALE enum encoding. + // The network payload only contains the event data (arguments), omitting the variant index + // because the `entry_id` in the header already serves as the identifier. + // However, the standard Rust `Decode` implementation for enums expects a leading index byte. + // Therefore, we use a custom Input to prepend the `entry_id` (as u8) to the payload without allocation. + let variant_index = entry_id as u8; + let mut input = EventInput { + idx: variant_index, + payload, + first: true, + }; + Decode::decode(&mut input) } } #[cfg(test)] mod tests { use super::*; - io_struct_impl!(Add (value: u32) -> u32); - io_struct_impl!(Value () -> u32); - - #[test] - fn test_str_encode() { - const ADD: &[u8] = str_scale_encode!(Add); - assert_eq!(ADD, &[12, 65, 100, 100]); - - const VALUE: &[u8] = str_scale_encode!(Value); - assert_eq!(VALUE, &[20, 86, 97, 108, 117, 101]); - } + // Define Add with InterfaceId to test 3-arg macro (Service mode) + io_struct_impl!(Add (value: u32) -> u32, 0, InterfaceId::from_bytes_8([1, 2, 3, 4, 5, 6, 7, 8])); + // Define Value with 2-arg macro (Ctor/Legacy mode) + io_struct_impl!(Value () -> u32, 1); #[test] fn test_io_struct_impl() { - let add = Add::encode_params(42); - assert_eq!(add, &[12, 65, 100, 100, 42, 0, 0, 0]); - - let value = Add::encode_params_with_prefix("Counter", 42); - assert_eq!( - value, - &[ - 28, 67, 111, 117, 110, 116, 101, 114, 12, 65, 100, 100, 42, 0, 0, 0 - ] - ); - - let value = Value::encode_params(); - assert_eq!(value, &[20, 86, 97, 108, 117, 101]); - - let value = Value::encode_params_with_prefix("Counter"); - assert_eq!( - value, - &[ - 28, 67, 111, 117, 110, 116, 101, 114, 20, 86, 97, 108, 117, 101 - ] - ); + // Add is now a "Service" method, so encode takes route_idx + let route_idx = 5; + let add_specific = Add::encode_call(route_idx, 42); + + let expected_header_add = [ + 0x47, 0x4D, // magic ("GM") + 1, // version + 16, // hlen + 1, 2, 3, 4, 5, 6, 7, 8, // interface_id + 0, 0, // entry_id (0 for Add) + 5, // route_id + 0, // reserved + ]; + let expected_add_payload = [42, 0, 0, 0]; // 42u32 LE + + let mut expected_add_specific = Vec::new(); + expected_add_specific.extend_from_slice(&expected_header_add); + expected_add_specific.extend_from_slice(&expected_add_payload); + + assert_eq!(add_specific, expected_add_specific); + + let reply_payload = [42, 0, 0, 0]; + let mut reply_with_header = expected_add_specific.clone(); + reply_with_header.truncate(16); + reply_with_header.extend_from_slice(&reply_payload); + + // Decode uses the new helper method + let decoded = Add::decode_reply(route_idx, &reply_with_header).unwrap(); + assert_eq!(decoded, 42); + + // Value is "Ctor" mode, it uses InterfaceId::zero() + let value_encoded = Value::encode_call(0); + let expected_header_value = [ + 0x47, 0x4D, 1, 16, // magic, version, hlen + 0, 0, 0, 0, 0, 0, 0, 0, // interface_id (zero) + 1, 0, // entry_id (1 for Value) + 0, 0, // route_id 0 and reserved 0 + ]; + assert_eq!(value_encoded, expected_header_value); + + // Decode reply for Value + let mut value_reply = expected_header_value.to_vec(); + value_reply.extend_from_slice(&[123, 0, 0, 0]); // payload 123u32 + let decoded_value = Value::decode_reply(0, &value_reply).unwrap(); + assert_eq!(decoded_value, 123); } } diff --git a/rs/src/gstd/events.rs b/rs/src/gstd/events.rs index e5ad0e15..808b78a1 100644 --- a/rs/src/gstd/events.rs +++ b/rs/src/gstd/events.rs @@ -3,6 +3,7 @@ use crate::{Encode, Output, utils::MaybeUninitBufferWriter}; use core::marker::PhantomData; use gcore::stack_buffer; +use sails_idl_meta::InterfaceId; /// Trait for encoding events that can be emitted by Sails programs. /// @@ -36,6 +37,9 @@ pub trait SailsEvent: Encode { /// Returns the encoded event name as a byte slice. fn encoded_event_name(&self) -> &'static [u8]; + /// Returns `entry_id` for an event. + fn entry_id(&self) -> u16; + /// The number of bytes to skip when encoding the event. /// /// For enums, this is always 1 byte, which is reserved for the index of the event enum variant. @@ -50,14 +54,12 @@ fn with_optimized_event_encode T>( event: E, f: F, ) -> T { - let encoded_event_name = E::encoded_event_name(&event); let encoded_size = Encode::encoded_size(&event); let skip_bytes = E::skip_bytes(); - let size = prefix.len() + encoded_event_name.len() + encoded_size - skip_bytes; + let size = prefix.len() + encoded_size - skip_bytes; stack_buffer::with_byte_buffer(size, |buffer| { let mut buffer_writer = MaybeUninitBufferWriter::new(buffer); buffer_writer.write(prefix); - buffer_writer.write(encoded_event_name); buffer_writer.skip_next(skip_bytes); // skip the first byte, which is the index of the event enum variant Encode::encode_to(&event, &mut buffer_writer); buffer_writer.with_buffer(f) @@ -68,25 +70,32 @@ fn with_optimized_event_encode T>( /// /// This is lightweight and can be cloned. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EventEmitter { - route: &'static [u8], - _marker: PhantomData, +pub struct EventEmitter { + interface_id: InterfaceId, + route_idx: u8, + _marker: PhantomData, } -impl EventEmitter { - pub fn new(route: &'static [u8]) -> Self { +impl EventEmitter { + pub fn new(interface_id: InterfaceId, route_idx: u8) -> Self { Self { - route, + interface_id, + route_idx, _marker: PhantomData, } } } -impl EventEmitter { +impl EventEmitter { /// Emits an event. #[cfg(target_arch = "wasm32")] - pub fn emit_event(&mut self, event: T) -> crate::errors::Result<()> { - with_optimized_event_encode(self.route, event, |payload| { + pub fn emit_event(&mut self, event: E) -> crate::errors::Result<()> { + let header = crate::meta::SailsMessageHeader::v1( + self.interface_id, + event.entry_id(), + self.route_idx, + ); + with_optimized_event_encode(header.to_bytes().as_slice(), event, |payload| { gstd::msg::send_bytes(gstd::ActorId::zero(), payload, 0)?; Ok(()) }) @@ -94,7 +103,7 @@ impl EventEmitter { #[cfg(not(target_arch = "wasm32"))] #[cfg(not(feature = "std"))] - pub fn emit_event(&mut self, _event: T) -> crate::errors::Result<()> { + pub fn emit_event(&mut self, _event: E) -> crate::errors::Result<()> { unimplemented!( "`emit_event` is implemented only for the wasm32 architecture and the std future" ) @@ -123,19 +132,19 @@ impl EventEmitter { impl EventEmitter { /// Emits an event. pub fn emit_event(&mut self, event: T) -> crate::errors::Result<()> { - event_registry::push_event(self.route, event); + event_registry::push_event(self.route_idx, event); Ok(()) } #[cfg(feature = "ethexe")] pub fn emit_eth_event(&mut self, event: T) -> crate::errors::Result<()> { - event_registry::push_event(self.route, event); + event_registry::push_event(self.route_idx, event); Ok(()) } /// Takes the events emitted for this route and returns them as a `Vec`. pub fn take_events(&mut self) -> crate::Vec { - event_registry::take_events(self.route).unwrap_or_else(|| crate::Vec::new()) + event_registry::take_events(self.route_idx).unwrap_or_else(|| crate::Vec::new()) } } @@ -145,7 +154,7 @@ mod event_registry { use core::any::{Any, TypeId}; use std::{boxed::Box, collections::BTreeMap, sync::Mutex, vec::Vec}; - type Key = (&'static [u8], TypeId); + type Key = (u8, TypeId); std::thread_local! { /// thread-local registry mapping `(key, TypeId)` -> boxed `Vec` @@ -154,7 +163,7 @@ mod event_registry { /// Push a `value: T` onto the `Vec` stored under `key`. /// If none exists yet, we create a `Vec` for that `(key,TypeId::of::())`. - pub(super) fn push_event(key: &'static [u8], value: T) { + pub(super) fn push_event(key: u8, value: T) { ROUTE_EVENTS.with(|mtx| { let mut map = mtx.lock().expect("failed to lock ROUTE_EVENTS mutex"); let slot = map @@ -170,7 +179,7 @@ mod event_registry { } /// Take `Vec` for the given `key`, or `None` if nothing was ever pushed. - pub(super) fn take_events(key: &'static [u8]) -> Option> { + pub(super) fn take_events(key: u8) -> Option> { ROUTE_EVENTS.with(|mtx| { let mut map = mtx.lock().expect("failed to lock ROUTE_EVENTS mutex"); map.remove(&(key, TypeId::of::())).map(|boxed| { @@ -190,12 +199,12 @@ mod event_registry { #[test] fn event_registry() { - push_event(b"/foo", 42_u32); - push_event(b"/foo", 7_u32); + push_event(1, 42_u32); + push_event(1, 7_u32); - assert_eq!(take_events::(b"/foo"), Some(vec![42, 7])); - assert!(take_events::(b"/foo").is_none()); // removed - assert!(take_events::(b"/foo").is_none()); // wrong type + assert_eq!(take_events::(1), Some(vec![42, 7])); + assert!(take_events::(1).is_none()); // removed + assert!(take_events::(1).is_none()); // wrong type } } } @@ -218,6 +227,13 @@ mod tests { TestEvents::Event2 { .. } => &[24, 69, 118, 101, 110, 116, 50], } } + + fn entry_id(&self) -> u16 { + match self { + TestEvents::Event1(_) => 0, + TestEvents::Event2 { .. } => 1, + } + } } #[test] @@ -226,16 +242,13 @@ mod tests { assert_eq!(event.encode(), &[0, 42, 0, 0, 0]); with_optimized_event_encode(&[1, 2, 3], event, |payload| { - assert_eq!( - payload, - [1, 2, 3, 24, 69, 118, 101, 110, 116, 49, 42, 00, 00, 00] - ); + assert_eq!(payload, [1, 2, 3, 42, 00, 00, 00]); }); let event = TestEvents::Event2 { p1: 43 }; assert_eq!(event.encode(), &[1, 43, 0]); with_optimized_event_encode(&[], event, |payload| { - assert_eq!(payload, [24, 69, 118, 101, 110, 116, 50, 43, 00]); + assert_eq!(payload, [43, 00]); }); } } diff --git a/rs/src/gstd/mod.rs b/rs/src/gstd/mod.rs index 14c2cc64..d15d4706 100644 --- a/rs/src/gstd/mod.rs +++ b/rs/src/gstd/mod.rs @@ -9,12 +9,14 @@ pub use gstd::handle_signal; #[doc(hidden)] pub use gstd::{async_init, async_main, handle_reply_with_hook, message_loop}; pub use gstd::{debug, exec, msg}; +use sails_idl_meta::InterfaceId; #[doc(hidden)] pub use sails_macros::{event, export, program, service}; pub use syscalls::Syscall; use crate::{ errors::{Error, Result, RtlError}, + meta::SailsMessageHeader, prelude::{any::TypeId, *}, utils::MaybeUninitBufferWriter, }; @@ -62,7 +64,7 @@ pub fn unknown_input_panic(message: &str, input: &[u8]) -> ! { } } -struct HexSlice>(T); +pub struct HexSlice>(pub T); impl> core::fmt::Display for HexSlice { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -95,46 +97,52 @@ impl> core::fmt::Debug for HexSlice { } pub trait InvocationIo { - const ROUTE: &'static [u8]; + const INTERFACE_ID: InterfaceId; + const ENTRY_ID: u16; type Params: Decode; - const ASYNC: bool; - - fn check_asyncness(payload: impl AsRef<[u8]>) -> Result { - let value = payload.as_ref(); - if !value.starts_with(Self::ROUTE) { - return Err(Error::Rtl(RtlError::InvocationPrefixMismatches)); - } - - Ok(Self::ASYNC) - } fn decode_params(payload: impl AsRef<[u8]>) -> Result { let mut value = payload.as_ref(); - if !value.starts_with(Self::ROUTE) { + let header: SailsMessageHeader = Decode::decode(&mut value).map_err(Error::Codec)?; + if header.interface_id() != Self::INTERFACE_ID { + return Err(Error::Rtl(RtlError::InvocationPrefixMismatches)); + } + if header.entry_id() != Self::ENTRY_ID { return Err(Error::Rtl(RtlError::InvocationPrefixMismatches)); } - value = &value[Self::ROUTE.len()..]; - Decode::decode(&mut value).map_err(Error::Codec) + let value: Self::Params = Decode::decode(&mut value).map_err(Error::Codec)?; + Ok(value) } fn with_optimized_encode( value: &T, - prefix: &[u8], + route_idx: u8, f: impl FnOnce(&[u8]) -> R, ) -> R { - let size = prefix.len() + Self::ROUTE.len() + Encode::encoded_size(value); + let header = SailsMessageHeader::v1(Self::INTERFACE_ID, Self::ENTRY_ID, route_idx); + let size = 16 + Encode::encoded_size(value); stack_buffer::with_byte_buffer(size, |buffer| { let mut buffer_writer = MaybeUninitBufferWriter::new(buffer); - - buffer_writer.write(prefix); - buffer_writer.write(Self::ROUTE); + Encode::encode_to(&header, &mut buffer_writer); Encode::encode_to(value, &mut buffer_writer); - buffer_writer.with_buffer(f) }) } +} - fn is_empty_tuple() -> bool { - TypeId::of::() == TypeId::of::<()>() - } +pub fn with_optimized_encode( + value: &T, + // prefix: &[u8], + f: impl FnOnce(&[u8]) -> R, +) -> R { + let size = Encode::encoded_size(value); + stack_buffer::with_byte_buffer(size, |buffer| { + let mut buffer_writer = MaybeUninitBufferWriter::new(buffer); + Encode::encode_to(value, &mut buffer_writer); + buffer_writer.with_buffer(f) + }) +} + +pub fn is_empty_tuple() -> bool { + TypeId::of::() == TypeId::of::<()>() } diff --git a/rs/src/gstd/services.rs b/rs/src/gstd/services.rs index f13f57e5..163d6ac7 100644 --- a/rs/src/gstd/services.rs +++ b/rs/src/gstd/services.rs @@ -1,21 +1,49 @@ -use crate::gstd::EventEmitter; +use crate::{gstd::EventEmitter, meta::InterfaceId}; -pub trait Service { +#[macro_export] +macro_rules! hash_fn { + // accept: command ... + ( + command $name:ident ( $( $ty:ty ),* $(,)? ) -> $reply:ty $(| $throws:ty )? + ) => { + $crate::hash_fn!(@impl "command" $name ( $( $ty ),* ) -> $reply $(| $throws )?) + }; + + // accept: query ... + ( + query $name:ident ( $( $ty:ty ),* $(,)? ) -> $reply:ty $(| $throws:ty )? + ) => { + $crate::hash_fn!(@impl "query" $name ( $( $ty ),* ) -> $reply $(| $throws )?) + }; + + (@impl $kind:literal + $name:ident ( $( $ty:ty ),* ) -> $reply:ty $(| $throws:ty )? + ) => {{ + let mut fn_hash = $crate::keccak_const::Keccak256::new(); + fn_hash = fn_hash.update($kind.as_bytes()).update(stringify!($name).as_bytes()); + $( fn_hash = fn_hash.update(&<$ty as $crate::sails_reflect_hash::ReflectHash>::HASH); )* + fn_hash = fn_hash.update(b"res").update(&<$reply as $crate::sails_reflect_hash::ReflectHash>::HASH); + $( fn_hash = fn_hash.update(b"throws").update(&<$throws as $crate::sails_reflect_hash::ReflectHash>::HASH); )? + fn_hash.finalize() + }}; +} + +pub trait Service: Sized { type Exposure: Exposure; - fn expose(self, route: &'static [u8]) -> Self::Exposure; + fn expose(self, route_idx: u8) -> Self::Exposure; } pub trait Exposure { - fn route(&self) -> &'static [u8]; - fn check_asyncness(input: &[u8]) -> Option; + fn interface_id() -> InterfaceId; + fn route_idx(&self) -> u8; + fn check_asyncness(interface_id: InterfaceId, entry_id: u16) -> Option; } pub trait ExposureWithEvents: Exposure { type Events; fn emitter(&self) -> EventEmitter { - let route = self.route(); - EventEmitter::new(route) + EventEmitter::new(Self::interface_id(), self.route_idx()) } } diff --git a/rs/src/lib.rs b/rs/src/lib.rs index 61fb7ba5..d0391329 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -21,7 +21,6 @@ pub use spin; mod builder; pub mod client; pub mod errors; -pub mod header; #[cfg(feature = "gclient")] #[cfg(not(target_arch = "wasm32"))] pub use gclient; diff --git a/rs/src/routing.rs b/rs/src/routing.rs new file mode 100644 index 00000000..7aa765ba --- /dev/null +++ b/rs/src/routing.rs @@ -0,0 +1,64 @@ +use crate::meta::{AnyServiceIds, InterfaceId, ServiceMeta}; + +/// Count the total number of base services recursively for a service +pub const fn count_base_services() -> usize { + let mut counter = 0; + + let direct_base_services = S::BASE_SERVICES_IDS; + let mut idx = 0; + while idx != direct_base_services.len() { + let any_svc_meta_fn = direct_base_services[idx]; + count_base_services_recursive(&mut counter, any_svc_meta_fn); + idx += 1; + } + + counter +} + +const fn count_base_services_recursive(counter: &mut usize, base: AnyServiceIds) { + *counter += 1; + + let base_services = base.base_services; + let mut idx = 0; + while idx != base_services.len() { + count_base_services_recursive(counter, base_services[idx]); + idx += 1; + } +} + +/// Generate interface IDs array from exposed services +pub const fn interface_ids( + exposed_services: &'static [AnyServiceIds], +) -> [(InterfaceId, u8); N] { + let mut output = [(InterfaceId([0u8; 8]), 0u8); N]; + + let mut exposed_svc_idx = 0; + let mut output_offset = 0; + let mut route_id = 1; + while exposed_svc_idx != exposed_services.len() { + let service = exposed_services[exposed_svc_idx]; + fill_interface_ids_recursive(&mut output, &mut output_offset, service, route_id); + exposed_svc_idx += 1; + route_id += 1; + } + + assert!(output_offset == N, "Mismatched interface IDs count"); + + output +} + +const fn fill_interface_ids_recursive( + arr: &mut [(InterfaceId, u8)], + offset: &mut usize, + service: AnyServiceIds, + route_id: u8, +) { + arr[*offset] = (service.interface_id, route_id); + *offset += 1; + let base_services = service.base_services; + let mut idx = 0; + while idx != base_services.len() { + fill_interface_ids_recursive(arr, offset, base_services[idx], route_id); + idx += 1; + } +} diff --git a/rs/src/solidity.rs b/rs/src/solidity.rs index 5dcf9763..573f9fd1 100644 --- a/rs/src/solidity.rs +++ b/rs/src/solidity.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use alloy_primitives::Selector; +use sails_idl_meta::{InterfaceId, ServiceMeta}; #[cfg(any(feature = "gtest", all(feature = "gstd", target_arch = "wasm32")))] pub(crate) const ETH_EVENT_ADDR: gstd::ActorId = gstd::ActorId::new([ @@ -8,19 +9,20 @@ pub(crate) const ETH_EVENT_ADDR: gstd::ActorId = gstd::ActorId::new([ ]); pub type MethodExpo = ( - &'static [u8], // Method route - &'static str, // Method name - &'static str, // Method parameters types - &'static str, // Method callback parameters types + InterfaceId, // Service interface id + u16, // Method entry id + &'static str, // Method name + &'static str, // Method parameters types + &'static str, // Method callback parameters types ); pub type ServiceExpo = ( &'static str, // Service expo name - &'static [u8], // Service route + u8, // Service route idx &'static [MethodExpo], // Method routes ); -pub trait ServiceSignature { +pub trait ServiceSignature: ServiceMeta { const METHODS: &'static [MethodExpo]; } @@ -103,9 +105,8 @@ where let mut sigs = [[0u8; 4]; N]; let mut ctor_idx = 0; while ctor_idx < ::CTORS.len() { - let (_, name, params, _) = ::CTORS[ctor_idx]; + let (_, _, name, params, _) = ::CTORS[ctor_idx]; let selector = const_selector!(name, params); - Self::assert_selector_not_equals_ctor_routes(selector); sigs[ctor_idx] = selector; ctor_idx += 1; } @@ -116,7 +117,7 @@ where let mut sigs = [[0u8; 4]; N]; let mut ctor_idx = 0; while ctor_idx < ::CTORS.len() { - let (_, name, _, callback) = ::CTORS[ctor_idx]; + let (_, _, name, _, callback) = ::CTORS[ctor_idx]; sigs[ctor_idx] = const_selector!("replyOn_", name, callback); ctor_idx += 1; } @@ -131,9 +132,8 @@ where let (svc_name, _, methods) = ::SERVICES[svc_idx]; let mut method_idx = 0; while method_idx < methods.len() { - let (_, name, params, _) = methods[method_idx]; + let (_, _, name, params, _) = methods[method_idx]; let selector = const_selector!(svc_name, name, params); - Self::assert_selector_not_equals_method_routes(selector); sigs[sigs_idx] = selector; method_idx += 1; sigs_idx += 1; @@ -143,16 +143,16 @@ where sigs } - pub const fn method_routes() -> [(&'static [u8], &'static [u8]); N] { - let mut routes: [(&'static [u8], &'static [u8]); N] = [(&[], &[]); N]; + pub const fn method_routes() -> [(InterfaceId, u16, u8); N] { + let mut routes: [(InterfaceId, u16, u8); N] = [(InterfaceId::zero(), 0, 0); N]; let mut map_idx = 0; let mut svc_idx = 0; while svc_idx < ::SERVICES.len() { - let (_, svc_route, methods) = ::SERVICES[svc_idx]; + let (_, route_idx, methods) = ::SERVICES[svc_idx]; let mut method_idx = 0; while method_idx < methods.len() { - let (route, ..) = methods[method_idx]; - routes[map_idx] = (svc_route, route); + let (interface_id, entry_id, ..) = methods[method_idx]; + routes[map_idx] = (interface_id, entry_id, route_idx); method_idx += 1; map_idx += 1; } @@ -169,7 +169,7 @@ where let (svc_name, _, methods) = ::SERVICES[svc_idx]; let mut method_idx = 0; while method_idx < methods.len() { - let (_, name, _, callback) = methods[method_idx]; + let (_, _, name, _, callback) = methods[method_idx]; sigs[sigs_idx] = const_selector!("replyOn_", svc_name, name, callback); method_idx += 1; sigs_idx += 1; @@ -178,56 +178,6 @@ where } sigs } - - const fn assert_selector_not_equals_method_routes(selector: [u8; 4]) { - let mut svc_idx = 0; - while svc_idx < ::SERVICES.len() { - let (_, svc_route, methods) = ::SERVICES[svc_idx]; - let mut method_idx = 0; - while method_idx < methods.len() { - let (route, ..) = methods[method_idx]; - assert!(!selector_equals(selector, svc_route, route)); - method_idx += 1; - } - svc_idx += 1; - } - } - - const fn assert_selector_not_equals_ctor_routes(selector: [u8; 4]) { - let mut ctor_idx = 0; - while ctor_idx < ::CTORS.len() { - let (route, ..) = ::CTORS[ctor_idx]; - assert!(!selector_equals(selector, route, &[])); - ctor_idx += 1; - } - } -} - -/// Compares a 4-byte selector array against the concatenation of two input byte slices. -/// -/// This function checks whether the **first 4 bytes** of the concatenated `first` and `second` slices -/// exactly match the `selector`. It does not require `first` or `second` to be of any specific length, -/// but the **combined length must be at least 4** for the function to return `true`. -/// -/// Any mismatch in the first 4 bytes results in `false`. -const fn selector_equals(selector: [u8; 4], first: &[u8], second: &[u8]) -> bool { - let mut i = 0; - while i < first.len() && i < selector.len() { - if selector[i] != first[i] { - return false; - } - i += 1; - } - let mut j = 0; - while j < second.len() && i < selector.len() { - if selector[i] != second[j] { - return false; - } - i += 1; - j += 1; - } - // False if we didn't match full len - i == selector.len() } #[cfg(test)] @@ -257,17 +207,30 @@ mod tests { struct Prg; struct Svc; struct ExtendedSvc; + #[derive(crate::TypeInfo)] + enum Empty {} + + impl ServiceMeta for Svc { + type CommandsMeta = Empty; + type QueriesMeta = Empty; + type EventsMeta = Empty; + const BASE_SERVICES: &'static [sails_idl_meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(1); + } impl ServiceSignature for Svc { const METHODS: &[MethodExpo] = &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(1), + 0, "DoThis", <<(u32, String, u128) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(1), + 1, "This", <<(bool, u128) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, @@ -275,18 +238,29 @@ mod tests { ]; } + impl ServiceMeta for ExtendedSvc { + type CommandsMeta = Empty; + type QueriesMeta = Empty; + type EventsMeta = Empty; + const BASE_SERVICES: &'static [sails_idl_meta::BaseServiceMeta] = &[]; + const ASYNC: bool = false; + const INTERFACE_ID: InterfaceId = InterfaceId::from_u64(2); + } + impl ServiceSignature for ExtendedSvc { const METHODS: &[MethodExpo] = const_concat_slices!( , &[ ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(2), + 0, "DoThis", <<(u32, String, u128,) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, ), ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(2), + 1, "This", <<(bool, u128,) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, @@ -301,23 +275,16 @@ mod tests { + ::METHODS.len(); const CTORS: &[MethodExpo] = &[( - &[28u8, 68u8, 101u8, 102u8, 97u8, 117u8, 108u8, 116u8] as &[u8], + InterfaceId::zero(), + 0, "create", <<(u128,) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256,) as SolValue>::SolType as SolType>::SOL_NAME, )]; const SERVICES: &[ServiceExpo] = &[ - ( - "svc1", - &[16u8, 83u8, 118u8, 99u8, 49u8] as &[u8], - ::METHODS, - ), - ( - "svc2", - &[16u8, 83u8, 118u8, 99u8, 49u8] as &[u8], - ::METHODS, - ), + ("svc1", 1, ::METHODS), + ("svc2", 2, ::METHODS), ]; } @@ -325,20 +292,36 @@ mod tests { fn service_signature_extended() { assert_eq!(4, ExtendedSvc::METHODS.len()); + let do_this_ext = ( + InterfaceId::from_u64(2), + 0, + "DoThis", + "(uint32,string,uint128)", + "(bytes32,uint32)", + ); + let this_ext = ( + InterfaceId::from_u64(2), + 1, + "This", + <<(bool, u128) as SolValue>::SolType as SolType>::SOL_NAME, + <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, + ); let do_this = ( - &[24u8, 68u8, 111u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(1), + 0, "DoThis", "(uint32,string,uint128)", "(bytes32,uint32)", ); let this = ( - &[16u8, 84u8, 104u8, 105u8, 115u8] as &[u8], + InterfaceId::from_u64(1), + 1, "This", <<(bool, u128) as SolValue>::SolType as SolType>::SOL_NAME, <<(B256, u32) as SolValue>::SolType as SolType>::SOL_NAME, ); - assert_eq!(do_this, ExtendedSvc::METHODS[0]); - assert_eq!(this, ExtendedSvc::METHODS[1]); + assert_eq!(do_this_ext, ExtendedSvc::METHODS[0]); + assert_eq!(this_ext, ExtendedSvc::METHODS[1]); assert_eq!(do_this, ExtendedSvc::METHODS[2]); assert_eq!(this, ExtendedSvc::METHODS[3]); } @@ -384,47 +367,4 @@ mod tests { let sig_ctor = selector("replyOn_create(bytes32)"); assert_eq!(CTOR_CALLBACK_SIGS[0], sig_ctor.as_slice()); } - - #[test] - fn selector_equals_test_exact_match() { - let sel = *b"ABCD"; - assert!(selector_equals(sel, b"AB", b"CD")); - } - - #[test] - fn selector_equals_test_longer_second() { - let sel = *b"ABCD"; - assert!(selector_equals(sel, b"AB", b"CDEF")); - } - - #[test] - fn selector_equals_test_longer_first() { - let sel = *b"ABCD"; - assert!(selector_equals(sel, b"ABCDX", b"")); - } - - #[test] - fn selector_equals_test_short_inputs() { - let sel = *b"ABCD"; - assert!(selector_equals(sel, b"A", b"BCD")); - assert!(selector_equals(sel, b"", b"ABCD")); - } - - #[test] - fn selector_equals_test_mismatch_in_first() { - let sel = *b"XBCD"; - assert!(!selector_equals(sel, b"AB", b"CD")); - } - - #[test] - fn selector_equals_test_mismatch_in_second() { - let sel = *b"ABXD"; - assert!(!selector_equals(sel, b"AB", b"CD")); - } - - #[test] - fn selector_equals_test_mismatch_due_to_short_concat() { - let sel = *b"ABCD"; - assert!(!selector_equals(sel, b"A", b"B")); // only "AB" < 4 bytes - } } diff --git a/rs/src/types.rs b/rs/src/types.rs index c6fc549a..9100979b 100644 --- a/rs/src/types.rs +++ b/rs/src/types.rs @@ -2,6 +2,7 @@ pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128}; pub use gprimitives::{ActorId, CodeId, H160, H256, MessageId, NonZeroU256, U256}; #[cfg(feature = "gstd")] pub use gstd::BlockCount; +pub use sails_idl_meta::InterfaceId; pub type ValueUnit = u128;