1use crate::meta::SailsMessageHeader;
2use crate::prelude::*;
3use core::{
4 any::TypeId,
5 error::Error,
6 marker::PhantomData,
7 pin::Pin,
8 task::{Context, Poll},
9};
10use futures::Stream;
11pub use sails_idl_meta::{Identifiable, InterfaceId, MethodMeta};
12
13#[cfg(all(feature = "gtest", not(target_arch = "wasm32")))]
14mod gtest_env;
15#[cfg(all(feature = "gtest", not(target_arch = "wasm32")))]
16pub use gtest_env::*;
17
18#[cfg(all(feature = "gsdk", not(target_arch = "wasm32")))]
19mod gsdk_env;
20#[cfg(all(feature = "gsdk", not(target_arch = "wasm32")))]
21pub use gsdk_env::{GsdkEnv, GsdkError, GsdkParams};
22
23mod gstd_env;
24pub use gstd_env::{GstdEnv, GstdParams};
25
26pub(crate) const PENDING_CALL_INVALID_STATE: &str =
27 "PendingCall polled after completion or invalid state";
28pub(crate) const PENDING_CTOR_INVALID_STATE: &str =
29 "PendingCtor polled after completion or invalid state";
30
31pub type Route = &'static str;
35
36pub trait RouteHeader: Clone + core::fmt::Debug {}
38
39#[derive(Debug, Clone, Copy, Default)]
41pub struct RouteIdx(pub u8);
42impl RouteHeader for RouteIdx {}
43
44#[derive(Debug, Clone, Copy, Default)]
47pub struct RouteName(pub Route);
48impl RouteHeader for RouteName {}
49
50pub trait GearEnv: Clone {
53 type Params: Default;
54 type Error: Error;
55 type MessageState;
56
57 fn deploy<P: Program>(&self, code_id: CodeId, salt: Vec<u8>) -> Deployment<P, Self> {
58 Deployment::new(self.clone(), code_id, salt)
59 }
60}
61
62#[diagnostic::on_unimplemented(
69 message = "`{Self}` cannot create programs from within a program",
70 note = "on `ethexe`, programs are deployed via the L1, so `GstdEnv` does not implement `EnvWithCtor`"
71)]
72pub trait EnvWithCtor: GearEnv {}
73
74pub trait Program: Sized {
75 fn deploy(code_id: CodeId, salt: Vec<u8>) -> Deployment<Self, GstdEnv> {
76 Deployment::new(GstdEnv, code_id, salt)
77 }
78
79 fn client(program_id: ActorId) -> Actor<Self, GstdEnv> {
80 Actor::new(GstdEnv, program_id)
81 }
82}
83
84#[derive(Debug, Clone)]
85pub struct Deployment<A, E: GearEnv = GstdEnv> {
86 env: E,
87 code_id: CodeId,
88 salt: Vec<u8>,
89 _phantom: PhantomData<A>,
90}
91
92impl<A, E: GearEnv> Deployment<A, E> {
93 pub fn new(env: E, code_id: CodeId, salt: Vec<u8>) -> Self {
94 Deployment {
95 env,
96 code_id,
97 salt,
98 _phantom: PhantomData,
99 }
100 }
101
102 pub fn with_env<N: GearEnv>(self, env: &N) -> Deployment<A, N> {
103 let Self {
104 env: _,
105 code_id,
106 salt,
107 _phantom: _,
108 } = self;
109 Deployment {
110 env: env.clone(),
111 code_id,
112 salt,
113 _phantom: PhantomData,
114 }
115 }
116
117 pub fn pending_ctor<T>(self, args: T::Params) -> PendingCtor<A, T, E>
119 where
120 T: ServiceCall<Route = RouteIdx>,
121 {
122 PendingCtor::new(self.env, self.code_id, self.salt, RouteIdx(0), args)
123 }
124
125 pub fn pending_ctor_v1<T>(self, args: T::Params) -> PendingCtor<A, T, E>
127 where
128 T: ServiceCall<Route = RouteName>,
129 {
130 PendingCtor::new(self.env, self.code_id, self.salt, RouteName(""), args)
131 }
132}
133
134#[derive(Debug, Clone)]
135pub struct Actor<A, E: GearEnv = GstdEnv> {
136 env: E,
137 id: ActorId,
138 _phantom: PhantomData<A>,
139}
140
141impl<A, E: GearEnv> Actor<A, E> {
142 pub fn new(env: E, id: ActorId) -> Self {
143 Actor {
144 env,
145 id,
146 _phantom: PhantomData,
147 }
148 }
149
150 pub fn id(&self) -> ActorId {
151 self.id
152 }
153
154 pub fn with_env<N: GearEnv>(self, env: &N) -> Actor<A, N> {
155 let Self {
156 env: _,
157 id,
158 _phantom: _,
159 } = self;
160 Actor {
161 env: env.clone(),
162 id,
163 _phantom: PhantomData,
164 }
165 }
166
167 pub fn with_actor_id(mut self, actor_id: ActorId) -> Self {
168 self.id = actor_id;
169 self
170 }
171
172 pub fn service<S>(&self, route_idx: u8) -> Service<S, E> {
174 Service::new(self.env.clone(), self.id, RouteIdx(route_idx))
175 }
176
177 pub fn service_v1<S>(&self, name: Route) -> Service<S, E, RouteName> {
179 Service::new(self.env.clone(), self.id, RouteName(name))
180 }
181}
182
183#[derive(Debug, Clone)]
184pub struct Service<S, E: GearEnv = GstdEnv, R: RouteHeader = RouteIdx> {
185 env: E,
186 actor_id: ActorId,
187 route: R,
188 _phantom: PhantomData<S>,
189}
190
191impl<S, E: GearEnv, R: RouteHeader> Service<S, E, R> {
192 pub fn new(env: E, actor_id: ActorId, route: R) -> Self {
193 Service {
194 env,
195 actor_id,
196 route,
197 _phantom: PhantomData,
198 }
199 }
200
201 pub fn actor_id(&self) -> ActorId {
202 self.actor_id
203 }
204
205 pub fn with_actor_id(mut self, actor_id: ActorId) -> Self {
206 self.actor_id = actor_id;
207 self
208 }
209
210 pub fn pending_call<T: ServiceCall<Route = R>>(&self, args: T::Params) -> PendingCall<T, E> {
211 PendingCall::new(self.env.clone(), self.actor_id, self.route.clone(), args)
212 }
213
214 pub fn base_service<B>(&self) -> Service<B, E, R> {
215 Service::new(self.env.clone(), self.actor_id, self.route.clone())
216 }
217
218 #[cfg(not(target_arch = "wasm32"))]
219 pub fn decode_event<Ev: Event<R>>(
220 &self,
221 payload: impl AsRef<[u8]>,
222 ) -> Result<Ev, parity_scale_codec::Error> {
223 Ev::decode_event(&self.route, payload)
224 }
225
226 #[cfg(not(target_arch = "wasm32"))]
227 pub async fn listen(
228 &self,
229 ) -> Result<impl Stream<Item = (ActorId, S::Event)> + Unpin + use<S, E, R>, <E as GearEnv>::Error>
230 where
231 S: ServiceWithEvents<R>,
232 E: Listener<Error = <E as GearEnv>::Error>,
233 {
234 let self_id = self.actor_id;
235 let route = self.route.clone();
236 self.env
237 .listen(move |(actor_id, payload)| {
238 if actor_id != self_id {
239 return None;
240 }
241 S::Event::decode_event(&route, payload)
242 .ok()
243 .map(|e| (actor_id, e))
244 })
245 .await
246 }
247}
248
249impl<S, E: GearEnv> Service<S, E, RouteIdx> {
251 pub fn interface_id(&self) -> InterfaceId
252 where
253 S: Identifiable,
254 {
255 S::INTERFACE_ID
256 }
257
258 pub fn route_idx(&self) -> u8 {
259 self.route.0
260 }
261}
262
263#[cfg(not(target_arch = "wasm32"))]
264pub trait ServiceWithEvents<R: RouteHeader = RouteIdx> {
265 type Event: Event<R>;
266}
267
268pin_project_lite::pin_project! {
269 pub struct PendingCall<T: ServiceCall, E: GearEnv = GstdEnv> {
270 env: E,
271 destination: ActorId,
272 route: T::Route,
273 params: Option<E::Params>,
274 args: Option<T::Params>,
275 #[pin]
276 state: Option<E::MessageState>
277 }
278}
279
280impl<T: ServiceCall, E: GearEnv> PendingCall<T, E> {
281 pub fn new(env: E, destination: ActorId, route: T::Route, args: T::Params) -> Self {
282 PendingCall {
283 env,
284 destination,
285 route,
286 params: None,
287 args: Some(args),
288 state: None,
289 }
290 }
291
292 pub fn with_destination(mut self, actor_id: ActorId) -> Self {
293 self.destination = actor_id;
294 self
295 }
296
297 pub fn with_params(mut self, f: impl FnOnce(E::Params) -> E::Params) -> Self {
298 self.params = Some(f(self.params.unwrap_or_default()));
299 self
300 }
301
302 pub fn encode_call(mut self) -> Vec<u8> {
303 let (payload, _) = self.take_encoded_args_and_params();
304 payload
305 }
306
307 #[inline]
308 pub(crate) fn take_encoded_args_and_params(&mut self) -> (Vec<u8>, E::Params) {
309 let args = self
310 .args
311 .take()
312 .unwrap_or_else(|| panic!("{PENDING_CALL_INVALID_STATE}"));
313 let payload = T::encode_call(&self.route, &args);
314 let params = self.params.take().unwrap_or_default();
315 (payload, params)
316 }
317}
318
319pub trait PendingCtorOutput<A, E: GearEnv> {
320 type Output;
321
322 fn map_result(self, env: E, id: ActorId) -> Self::Output;
323
324 fn actor(output: Self::Output) -> Actor<A, E>;
325}
326
327impl<A, E: GearEnv> PendingCtorOutput<A, E> for () {
328 type Output = Actor<A, E>;
329
330 fn map_result(self, env: E, id: ActorId) -> Self::Output {
331 Actor::new(env, id)
332 }
333
334 fn actor(output: Self::Output) -> Actor<A, E> {
335 output
336 }
337}
338
339impl<A, E: GearEnv, Err: core::fmt::Debug> PendingCtorOutput<A, E> for Result<(), Err> {
340 type Output = Result<Actor<A, E>, Err>;
341
342 fn map_result(self, env: E, id: ActorId) -> Self::Output {
343 self.map(|_| Actor::new(env, id))
344 }
345
346 fn actor(output: Self::Output) -> Actor<A, E> {
347 output.expect("PendingCtor output is not Ok")
348 }
349}
350
351pin_project_lite::pin_project! {
352 pub struct PendingCtor<A, T: ServiceCall, E: GearEnv = GstdEnv> {
353 env: E,
354 code_id: CodeId,
355 route: T::Route,
356 params: Option<E::Params>,
357 salt: Option<Vec<u8>>,
358 args: Option<T::Params>,
359 _actor: PhantomData<A>,
360 #[pin]
361 state: Option<E::MessageState>,
362 program_id: Option<ActorId>,
363 }
364}
365
366impl<A, T: ServiceCall, E: GearEnv> PendingCtor<A, T, E> {
367 pub fn new(env: E, code_id: CodeId, salt: Vec<u8>, route: T::Route, args: T::Params) -> Self {
368 PendingCtor {
369 env,
370 code_id,
371 route,
372 params: None,
373 salt: Some(salt),
374 args: Some(args),
375 state: None,
376 program_id: None,
377 _actor: PhantomData,
378 }
379 }
380
381 pub fn with_params(mut self, f: impl FnOnce(E::Params) -> E::Params) -> Self {
382 self.params = Some(f(self.params.unwrap_or_default()));
383 self
384 }
385}
386
387pub trait ServiceCall {
390 type Route: RouteHeader;
391 type Params;
392 type Reply;
393 type Throws;
395 type Output;
396
397 fn encode_call(route: &Self::Route, value: &Self::Params) -> Vec<u8>;
398
399 fn decode_reply(
400 route: &Self::Route,
401 payload: impl AsRef<[u8]>,
402 ) -> Result<Self::Output, parity_scale_codec::Error>;
403
404 fn decode_error(
405 route: &Self::Route,
406 payload: impl AsRef<[u8]>,
407 ) -> Result<Self::Output, parity_scale_codec::Error>;
408}
409
410pub fn decode_with_header<T, M>(
415 route_idx: u8,
416 payload: impl AsRef<[u8]>,
417) -> Result<T, parity_scale_codec::Error>
418where
419 T: Decode + 'static,
420 M: MethodMeta + Identifiable,
421{
422 let mut value = payload.as_ref();
423 if is_empty_tuple::<T>() {
424 return Decode::decode(&mut value);
425 }
426 let header = SailsMessageHeader::decode(&mut value)?;
427 if header.interface_id() != M::INTERFACE_ID {
428 return Err("Invalid reply interface_id".into());
429 }
430 if header.route_id() != route_idx {
431 return Err("Invalid reply route_idx".into());
432 }
433 if header.entry_id() != M::ENTRY_ID {
434 return Err("Invalid reply entry_id".into());
435 }
436 Decode::decode(&mut value)
437}
438
439pub fn is_empty_tuple<T>() -> bool
441where
442 T: 'static,
443{
444 TypeId::of::<T>() == TypeId::of::<()>()
445}
446
447pub trait ReplyError: Sized {
450 fn from_codec_error(err: parity_scale_codec::Error) -> Self;
452
453 fn userspace_panic_payload(&self) -> Option<&[u8]>;
455}
456
457pub fn decode_reply_or_throw<T: ServiceCall, E: ReplyError>(
463 route: &T::Route,
464 reply: Result<Vec<u8>, E>,
465) -> Result<T::Output, E> {
466 match reply {
467 Ok(payload) => T::decode_reply(route, payload).map_err(E::from_codec_error),
468 Err(err) => {
469 if let Some(payload) = err.userspace_panic_payload()
470 && let Ok(reply) = T::decode_error(route, payload)
471 {
472 return Ok(reply);
473 }
474 Err(err)
475 }
476 }
477}
478
479pub fn encode_call_optimized<T, R>(
482 route_idx: u8,
483 value: &T::Params,
484 f: impl FnOnce(&[u8]) -> R,
485) -> R
486where
487 T: ServiceCall<Route = RouteIdx> + MethodMeta + Identifiable,
488 T::Params: Encode,
489{
490 encode_call_optimized_with_id::<T, R>(T::INTERFACE_ID, T::ENTRY_ID, route_idx, value, f)
491}
492
493pub fn encode_call_optimized_with_id<T, R>(
494 interface_id: InterfaceId,
495 entry_id: u16,
496 route_idx: u8,
497 value: &T::Params,
498 f: impl FnOnce(&[u8]) -> R,
499) -> R
500where
501 T: ServiceCall<Route = RouteIdx>,
502 T::Params: Encode,
503{
504 let header = SailsMessageHeader::new(
505 crate::meta::Version::v1(),
506 crate::meta::HeaderLength::new(crate::meta::MINIMAL_HLEN).unwrap(),
507 interface_id,
508 route_idx,
509 entry_id,
510 );
511 let size = (crate::meta::MINIMAL_HLEN as usize) + Encode::encoded_size(value);
512 gcore::stack_buffer::with_byte_buffer(size, |buffer| {
513 let mut buffer_writer = crate::utils::MaybeUninitBufferWriter::new(buffer);
514 header.encode_to(&mut buffer_writer);
515 Encode::encode_to(value, &mut buffer_writer);
516 buffer_writer.with_buffer(f)
517 })
518}
519
520#[macro_export]
521macro_rules! params_struct_impl {
522 (
523 $env:ident,
524 $name:ident { $( $(#[$attr:meta])* $vis:vis $field:ident: $ty:ty ),* $(,)? }
525 ) => {
526 #[derive(Debug, Default)]
527 pub struct $name {
528 $(
529 $(#[$attr])* $vis $field : Option< $ty >,
530 )*
531 }
532
533 impl $name {
534 $(
535 paste::paste! {
536 $(#[$attr])*
537 pub fn [<with_ $field>](mut self, $field: $ty) -> Self {
538 self.$field = Some($field);
539 self
540 }
541 }
542 )*
543 }
544
545 impl<A, T: $crate::client::ServiceCall> $crate::client::PendingCtor<A, T, $env> {
546 $(
547 paste::paste! {
548 $(#[$attr])*
549 pub fn [<with_ $field>](self, $field: $ty) -> Self {
550 self.with_params(|params| params.[<with_ $field>]($field))
551 }
552 }
553 )*
554 }
555
556 impl<T: $crate::client::ServiceCall> $crate::client::PendingCall<T, $env> {
557 $(
558 paste::paste! {
559 $(#[$attr])*
560 pub fn [<with_ $field>](self, $field: $ty) -> Self {
561 self.with_params(|params| params.[<with_ $field>]($field))
562 }
563 }
564 )*
565 }
566 };
567}
568
569#[macro_export]
570macro_rules! params_for_pending_impl {
571 (
572 $env:ident,
573 $name:ident { $( $(#[$attr:meta])* $vis:vis $field:ident: $ty:ty ),* $(,)? }
574 ) => {
575 impl $name {
576 $(
577 paste::paste! {
578 $(#[$attr])*
579 pub fn [<with_ $field>](mut self, $field: $ty) -> Self {
580 self.$field = Some($field);
581 self
582 }
583 }
584 )*
585 }
586
587 impl<A, T: $crate::client::ServiceCall> $crate::client::PendingCtor<A, T, $env> {
588 $(
589 paste::paste! {
590 $(#[$attr])*
591 pub fn [<with_ $field>](self, $field: $ty) -> Self {
592 self.with_params(|params| params.[<with_ $field>]($field))
593 }
594 }
595 )*
596 }
597
598 impl<T: $crate::client::ServiceCall> $crate::client::PendingCall<T, $env> {
599 $(
600 paste::paste! {
601 $(#[$attr])*
602 pub fn [<with_ $field>](self, $field: $ty) -> Self {
603 self.with_params(|params| params.[<with_ $field>]($field))
604 }
605 }
606 )*
607 }
608 };
609}
610
611#[macro_export]
612macro_rules! io_struct_impl {
613 (
615 $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty, $entry_id:expr, $interface_id:expr
616 ) => {
617 $crate::io_struct_impl!(@impl_base $name ( $( $param : $ty ),* ) -> $reply, $entry_id, $interface_id);
618
619 impl $crate::client::ServiceCall for $name {
620 type Route = $crate::client::RouteIdx;
621 type Params = ( $( $ty, )* );
622 type Reply = $reply;
623 type Throws = ();
624 type Output = $reply;
625
626 fn encode_call(route: &$crate::client::RouteIdx, value: &Self::Params) -> Vec<u8> {
627 let header = $crate::meta::SailsMessageHeader::new(
628 $crate::meta::Version::v1(),
629 $crate::meta::HeaderLength::new($crate::meta::MINIMAL_HLEN).unwrap(),
630 <$name as $crate::client::Identifiable>::INTERFACE_ID,
631 route.0,
632 <$name as $crate::client::MethodMeta>::ENTRY_ID,
633 );
634 let mut result = header.to_bytes();
635 $crate::prelude::Encode::encode_to(value, &mut result);
636 result
637 }
638
639 fn decode_reply(
640 route: &$crate::client::RouteIdx,
641 payload: impl AsRef<[u8]>,
642 ) -> Result<Self::Output, $crate::scale_codec::Error> {
643 $crate::client::decode_with_header::<Self::Reply, $name>(route.0, payload)
644 }
645
646 fn decode_error(
647 _route: &$crate::client::RouteIdx,
648 _payload: impl AsRef<[u8]>,
649 ) -> Result<Self::Output, $crate::scale_codec::Error> {
650 Err("Throws type is `()`".into())
651 }
652 }
653 };
654 (
656 $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty | $throws:ty, $entry_id:expr, $interface_id:expr
657 ) => {
658 $crate::io_struct_impl!(@impl_base $name ( $( $param : $ty ),* ) -> $reply, $entry_id, $interface_id);
659
660 impl $crate::client::ServiceCall for $name {
661 type Route = $crate::client::RouteIdx;
662 type Params = ( $( $ty, )* );
663 type Reply = $reply;
664 type Throws = $throws;
665 type Output = Result<$reply, $throws>;
666
667 fn encode_call(route: &$crate::client::RouteIdx, value: &Self::Params) -> Vec<u8> {
668 let header = $crate::meta::SailsMessageHeader::new(
669 $crate::meta::Version::v1(),
670 $crate::meta::HeaderLength::new($crate::meta::MINIMAL_HLEN).unwrap(),
671 <$name as $crate::client::Identifiable>::INTERFACE_ID,
672 route.0,
673 <$name as $crate::client::MethodMeta>::ENTRY_ID,
674 );
675 let mut result = header.to_bytes();
676 $crate::prelude::Encode::encode_to(value, &mut result);
677 result
678 }
679
680 fn decode_reply(
681 route: &$crate::client::RouteIdx,
682 payload: impl AsRef<[u8]>,
683 ) -> Result<Self::Output, $crate::scale_codec::Error> {
684 Ok(Ok($crate::client::decode_with_header::<Self::Reply, $name>(route.0, payload)?))
685 }
686
687 fn decode_error(
688 route: &$crate::client::RouteIdx,
689 payload: impl AsRef<[u8]>,
690 ) -> Result<Self::Output, $crate::scale_codec::Error> {
691 Ok(Err($crate::client::decode_with_header::<Self::Throws, $name>(route.0, payload)?))
692 }
693 }
694 };
695 (
697 $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty $( | $throws:ty )?, $entry_id:expr
698 ) => {
699 $crate::io_struct_impl!($name ( $( $param : $ty ),* ) -> $reply $( | $throws )?, $entry_id, $crate::meta::InterfaceId::zero());
700 };
701 (
703 @impl_base $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty, $entry_id:expr, $interface_id:expr
704 ) => {
705 pub struct $name(());
706 impl $name {
707 pub fn encode_call(route_idx: u8, $( $param: $ty, )* ) -> Vec<u8> {
709 <$name as $crate::client::ServiceCall>::encode_call(
710 &$crate::client::RouteIdx(route_idx), &( $( $param, )* )
711 )
712 }
713 pub fn decode_reply(route_idx: u8, payload: impl AsRef<[u8]>) -> Result<$reply, $crate::scale_codec::Error> {
715 $crate::client::decode_with_header::<$reply, $name>(route_idx, payload)
716 }
717 }
718 impl $crate::client::Identifiable for $name {
719 const INTERFACE_ID: $crate::meta::InterfaceId = $interface_id;
720 }
721 impl $crate::client::MethodMeta for $name {
722 const ENTRY_ID: u16 = $entry_id;
723 }
724 };
725}
726
727#[macro_export]
737macro_rules! io_struct_impl_v1 {
738 (
739 $name:ident ( $( $param:ident : $ty:ty ),* ) -> $reply:ty
740 ) => {
741 pub struct $name(());
742
743 impl $name {
744 pub fn encode_call(route: $crate::client::Route, $( $param: $ty, )* ) -> Vec<u8> {
745 <$name as $crate::client::ServiceCall>::encode_call(
746 &$crate::client::RouteName(route), &( $( $param, )* )
747 )
748 }
749
750 pub fn decode_reply(route: $crate::client::Route, payload: impl AsRef<[u8]>) -> Result<$reply, $crate::scale_codec::Error> {
751 <$name as $crate::client::ServiceCall>::decode_reply(
752 &$crate::client::RouteName(route),
753 payload,
754 )
755 }
756 }
757
758 impl $crate::client::ServiceCall for $name {
759 type Route = $crate::client::RouteName;
760 type Params = ( $( $ty, )* );
761 type Reply = $reply;
762 type Throws = ();
764 type Output = $reply;
765
766 fn encode_call(
767 route: &$crate::client::RouteName,
768 value: &Self::Params,
769 ) -> Vec<u8> {
770 use $crate::prelude::Encode as _;
771 let mut result = Vec::new();
772 if !route.0.is_empty() {
773 route.0.encode_to(&mut result);
774 }
775 stringify!($name).encode_to(&mut result);
776 value.encode_to(&mut result);
777 result
778 }
779
780 fn decode_reply(
781 route: &$crate::client::RouteName,
782 payload: impl AsRef<[u8]>,
783 ) -> Result<Self::Output, $crate::scale_codec::Error> {
784 use $crate::prelude::Decode as _;
785 let mut value = payload.as_ref();
786 if $crate::client::is_empty_tuple::<$reply>() {
787 return $crate::prelude::Decode::decode(&mut value);
788 }
789 if !route.0.is_empty() {
790 let svc = String::decode(&mut value)?;
791 if svc != route.0 {
792 return Err("Invalid reply service route".into());
793 }
794 }
795 let method = String::decode(&mut value)?;
796 if method != stringify!($name) {
797 return Err("Invalid reply method route".into());
798 }
799 $crate::prelude::Decode::decode(&mut value)
800 }
801
802 fn decode_error(
803 _route: &$crate::client::RouteName,
804 _payload: impl AsRef<[u8]>,
805 ) -> Result<Self::Output, $crate::scale_codec::Error> {
806 Err("Throws type is `()` for v1".into())
807 }
808 }
809 };
810}
811
812#[allow(unused_macros)]
813macro_rules! str_scale_encode {
814 ($s:ident) => {{
815 const S: &str = stringify!($s);
816 assert!(S.len() <= 63, "Ident too long for encoding");
817 const LEN: u8 = S.len() as u8;
818 const BYTES: [u8; LEN as usize + 1] = {
819 const fn to_array(s: &str) -> [u8; LEN as usize + 1] {
820 let bytes = s.as_bytes();
821 let mut out = [0u8; LEN as usize + 1];
822 out[0] = LEN << 2;
823 let mut i = 0;
824 while i < LEN as usize {
825 out[i + 1] = bytes[i];
826 i += 1;
827 }
828 out
829 }
830 to_array(S)
831 };
832 BYTES.as_slice()
833 }};
834}
835
836#[allow(async_fn_in_trait)]
837pub trait Listener {
838 type Error: Error;
839
840 async fn listen<E, F>(
841 &self,
842 f: F,
843 ) -> Result<impl Stream<Item = (ActorId, E)> + Unpin + use<Self, E, F>, Self::Error>
844 where
845 F: FnMut((ActorId, Vec<u8>)) -> Option<(ActorId, E)>;
846}
847
848#[cfg(not(target_arch = "wasm32"))]
849struct EventInput<'a> {
850 idx: u8,
851 payload: &'a [u8],
852 first: bool,
853}
854
855#[cfg(not(target_arch = "wasm32"))]
856impl<'a> parity_scale_codec::Input for EventInput<'a> {
857 fn remaining_len(&mut self) -> Result<Option<usize>, parity_scale_codec::Error> {
858 Ok(Some(1 + self.payload.len()))
859 }
860
861 fn read(&mut self, into: &mut [u8]) -> Result<(), parity_scale_codec::Error> {
862 if into.is_empty() {
863 return Ok(());
864 }
865 let (head, tail) = into.split_at_mut(if self.first { 1 } else { 0 });
866 if self.first {
867 head[0] = self.idx;
868 self.first = false;
869 }
870 if tail.is_empty() {
871 return Ok(());
872 }
873 if tail.len() > self.payload.len() {
874 return Err("Not enough data to fill buffer".into());
875 }
876 tail.copy_from_slice(&self.payload[..tail.len()]);
877 self.payload = &self.payload[tail.len()..];
878 Ok(())
879 }
880
881 fn read_byte(&mut self) -> Result<u8, parity_scale_codec::Error> {
882 if self.first {
883 self.first = false;
884 Ok(self.idx)
885 } else {
886 let b = *self.payload.first().ok_or("Not enough data to read byte")?;
887 self.payload = &self.payload[1..];
888 Ok(b)
889 }
890 }
891}
892
893#[cfg(not(target_arch = "wasm32"))]
898pub trait EventNames {
899 const EVENT_NAMES: &'static [Route];
900}
901
902#[cfg(not(target_arch = "wasm32"))]
905pub fn decode_event_v2<E>(
906 route_idx: u8,
907 payload: impl AsRef<[u8]>,
908) -> Result<E, parity_scale_codec::Error>
909where
910 E: Decode + Identifiable,
911{
912 let mut payload = payload.as_ref();
913
914 let header = SailsMessageHeader::decode(&mut payload)?;
915 if header.interface_id() != E::INTERFACE_ID {
916 return Err("Invalid event interface_id".into());
917 }
918 if header.route_id() != route_idx {
919 return Err("Invalid event route_idx".into());
920 }
921
922 let entry_id = header.entry_id();
923 if entry_id > 255 {
924 return Err("Entry ID exceeds u8 limit for SCALE enum".into());
925 }
926
927 let variant_index = entry_id as u8;
928 let mut input = EventInput {
929 idx: variant_index,
930 payload,
931 first: true,
932 };
933 Decode::decode(&mut input)
934}
935
936#[cfg(not(target_arch = "wasm32"))]
938pub fn decode_event_v1<E>(
939 route: Route,
940 payload: impl AsRef<[u8]>,
941) -> Result<E, parity_scale_codec::Error>
942where
943 E: Decode + EventNames,
944{
945 let mut payload = payload.as_ref();
946 let payload_route = String::decode(&mut payload)?;
947 if payload_route != route {
948 return Err("Invalid v1 event route".into());
949 }
950 let name = String::decode(&mut payload)?;
951 let idx = <E as EventNames>::EVENT_NAMES
952 .iter()
953 .position(|candidate| *candidate == name)
954 .ok_or("Unknown v1 event name")? as u8;
955 let mut input = EventInput {
956 idx,
957 payload,
958 first: true,
959 };
960 Decode::decode(&mut input)
961}
962
963#[cfg(not(target_arch = "wasm32"))]
967pub trait Event<R = RouteIdx>: Sized
968where
969 R: RouteHeader,
970{
971 fn decode_event(
972 route: &R,
973 payload: impl AsRef<[u8]>,
974 ) -> Result<Self, parity_scale_codec::Error>;
975}
976
977#[cfg(test)]
978mod tests {
979 use super::*;
980 io_struct_impl!(Add (value: u32) -> u32, 0, InterfaceId::from_bytes_8([1, 2, 3, 4, 5, 6, 7, 8]));
982 io_struct_impl!(Value () -> u32, 1);
984 io_struct_impl!(Sub (value: u32) -> u32 | String, 0, InterfaceId::from_bytes_8([1, 2, 3, 4, 5, 6, 7, 8]));
986
987 #[test]
988 fn test_io_struct_impl() {
989 let route_idx = RouteIdx(5u8);
991 let add_specific = Add::encode_call(route_idx.0, 42);
992
993 let expected_header_add = [
994 0x47, 0x4D, 1, 16, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 5, 0, ];
1002 let expected_add_payload = [42, 0, 0, 0]; let mut expected_add_specific = Vec::new();
1005 expected_add_specific.extend_from_slice(&expected_header_add);
1006 expected_add_specific.extend_from_slice(&expected_add_payload);
1007
1008 assert_eq!(add_specific, expected_add_specific);
1009
1010 let reply_payload = [42, 0, 0, 0];
1011 let mut reply_with_header = expected_add_specific.clone();
1012 reply_with_header.truncate(16);
1013 reply_with_header.extend_from_slice(&reply_payload);
1014
1015 let decoded = Add::decode_reply(route_idx.0, &reply_with_header).unwrap();
1016 assert_eq!(decoded, 42);
1017
1018 let value_encoded = Value::encode_call(0);
1020 let expected_header_value = [
1021 0x47, 0x4D, 1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ];
1026 assert_eq!(value_encoded, expected_header_value);
1027
1028 let mut value_reply = expected_header_value.to_vec();
1030 value_reply.extend_from_slice(&[123, 0, 0, 0]); let decoded_value = Value::decode_reply(0, &value_reply).unwrap();
1032 assert_eq!(decoded_value, 123);
1033 }
1034
1035 #[test]
1036 fn test_io_struct_impl_throws() {
1037 let route_idx = RouteIdx(5u8);
1038 let sub_specific = Sub::encode_call(route_idx.0, 42);
1039
1040 let expected_header_sub = [
1041 0x47, 0x4D, 1, 16, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 5, 0, ];
1049 let expected_sub_payload = [42, 0, 0, 0]; let mut expected_sub_specific = Vec::new();
1052 expected_sub_specific.extend_from_slice(&expected_header_sub);
1053 expected_sub_specific.extend_from_slice(&expected_sub_payload);
1054
1055 assert_eq!(sub_specific, expected_sub_specific);
1056
1057 let mut success_reply = expected_header_sub.to_vec();
1058 success_reply.extend_from_slice(&expected_sub_payload);
1059
1060 let decoded_success =
1061 <Sub as ServiceCall>::decode_reply(&route_idx, &success_reply).unwrap();
1062 assert_eq!(decoded_success, Ok(42));
1063 assert_eq!(Sub::decode_reply(route_idx.0, &success_reply).unwrap(), 42);
1064
1065 let error_message = String::from("boom");
1066 let mut error_reply = expected_header_sub.to_vec();
1067 error_reply.extend_from_slice(&error_message.encode());
1068
1069 let decoded_error = <Sub as ServiceCall>::decode_error(&route_idx, &error_reply).unwrap();
1070 assert_eq!(decoded_error, Err(error_message));
1071 }
1072
1073 #[test]
1074 fn test_io_struct_impl_v1() {
1075 io_struct_impl_v1!(DoThis (value: u32) -> u32);
1076
1077 let encoded = DoThis::encode_call("MyService", 42u32);
1079 let mut expected = Vec::new();
1080 "MyService".encode_to(&mut expected);
1081 "DoThis".encode_to(&mut expected);
1082 42u32.encode_to(&mut expected);
1083 assert_eq!(encoded, expected);
1084
1085 let decoded = DoThis::decode_reply("MyService", &encoded).unwrap();
1087 assert_eq!(decoded, 42u32);
1088 }
1089}