1#[doc(hidden)]
2#[cfg(feature = "ethexe")]
3pub use ethexe::{EthEvent, EthEventExpo};
4#[doc(hidden)]
5pub use events::{EventEmitter, SailsEvent};
6#[cfg(not(feature = "ethexe"))]
7#[doc(hidden)]
8pub use gstd::handle_signal;
9#[doc(hidden)]
10pub use gstd::{async_init, async_main, handle_reply_with_hook, message_loop};
11pub use gstd::{debug, exec, msg};
12#[doc(hidden)]
13pub use sails_macros::{event, export, program, service};
14pub use syscalls::Syscall;
15
16use crate::{
17 errors::{Error, Result, RtlError},
18 prelude::{any::TypeId, *},
19 utils::MaybeUninitBufferWriter,
20};
21use gcore::stack_buffer;
22
23#[cfg(feature = "ethexe")]
24mod ethexe;
25mod events;
26pub mod services;
27mod syscalls;
28
29pub struct CommandReply<T>(T, ValueUnit);
30
31impl<T> CommandReply<T> {
32 pub fn new(result: T) -> Self {
33 Self(result, 0)
34 }
35
36 pub fn with_value(self, value: ValueUnit) -> Self {
37 Self(self.0, value)
38 }
39
40 pub fn to_tuple(self) -> (T, ValueUnit) {
41 (self.0, self.1)
42 }
43}
44
45impl<T> From<T> for CommandReply<T> {
46 fn from(result: T) -> Self {
47 Self(result, 0)
48 }
49}
50
51impl<T> From<(T, ValueUnit)> for CommandReply<T> {
52 fn from(value: (T, ValueUnit)) -> Self {
53 Self(value.0, value.1)
54 }
55}
56
57pub fn unknown_input_panic(message: &str, input: &[u8]) -> ! {
58 let mut __input = input;
59 match String::decode(&mut __input) {
60 Ok(s) => panic!("{}: {}", message, s),
61 Err(_) => panic!("{}: {}", message, HexSlice(input)),
62 }
63}
64
65struct HexSlice<T: AsRef<[u8]>>(T);
66
67impl<T: AsRef<[u8]>> core::fmt::Display for HexSlice<T> {
68 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69 let slice = self.0.as_ref();
70 let len = slice.len();
71 let precision = f.precision().unwrap_or(4);
72
73 f.write_str("0x")?;
74 if len <= precision * 2 {
75 for byte in slice {
76 write!(f, "{byte:02x}")?;
77 }
78 } else {
79 for byte in &slice[..precision] {
80 write!(f, "{byte:02x}")?;
81 }
82 f.write_str("..")?;
83 for byte in &slice[len - precision..] {
84 write!(f, "{byte:02x}")?;
85 }
86 }
87 Ok(())
88 }
89}
90
91impl<T: AsRef<[u8]>> core::fmt::Debug for HexSlice<T> {
92 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
93 core::fmt::Display::fmt(self, f)
94 }
95}
96
97pub trait InvocationIo {
98 const ROUTE: &'static [u8];
99 type Params: Decode;
100 const ASYNC: bool;
101
102 fn check_asyncness(payload: impl AsRef<[u8]>) -> Result<bool> {
103 let value = payload.as_ref();
104 if !value.starts_with(Self::ROUTE) {
105 return Err(Error::Rtl(RtlError::InvocationPrefixMismatches));
106 }
107
108 Ok(Self::ASYNC)
109 }
110
111 fn decode_params(payload: impl AsRef<[u8]>) -> Result<Self::Params> {
112 let mut value = payload.as_ref();
113 if !value.starts_with(Self::ROUTE) {
114 return Err(Error::Rtl(RtlError::InvocationPrefixMismatches));
115 }
116 value = &value[Self::ROUTE.len()..];
117 Decode::decode(&mut value).map_err(Error::Codec)
118 }
119
120 fn with_optimized_encode<T: Encode, R>(
121 value: &T,
122 prefix: &[u8],
123 f: impl FnOnce(&[u8]) -> R,
124 ) -> R {
125 let size = prefix.len() + Self::ROUTE.len() + Encode::encoded_size(value);
126 stack_buffer::with_byte_buffer(size, |buffer| {
127 let mut buffer_writer = MaybeUninitBufferWriter::new(buffer);
128
129 buffer_writer.write(prefix);
130 buffer_writer.write(Self::ROUTE);
131 Encode::encode_to(value, &mut buffer_writer);
132
133 buffer_writer.with_buffer(f)
134 })
135 }
136
137 fn is_empty_tuple<T: 'static>() -> bool {
138 TypeId::of::<T>() == TypeId::of::<()>()
139 }
140}