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};
12use sails_idl_meta::{InterfaceId, MethodMeta};
13#[doc(hidden)]
14pub use sails_macros::{event, export, program, service};
15pub use syscalls::Syscall;
16
17pub const MAX_PANIC_PAYLOAD_SIZE: usize = 1024;
21
22use crate::{
23 errors::{Error, Result, RtlError},
24 meta::SailsMessageHeader,
25 prelude::{any::TypeId, *},
26 utils::MaybeUninitBufferWriter,
27};
28use gcore::stack_buffer;
29
30#[cfg(feature = "ethexe")]
31mod ethexe;
32mod events;
33mod macros;
34pub mod services;
35mod syscalls;
36
37pub struct CommandReply<T>(T, ValueUnit);
38
39impl<T> CommandReply<T> {
40 pub fn new(result: T) -> Self {
41 Self(result, 0)
42 }
43
44 pub fn with_value(self, value: ValueUnit) -> Self {
45 Self(self.0, value)
46 }
47
48 pub fn to_tuple(self) -> (T, ValueUnit) {
49 (self.0, self.1)
50 }
51}
52
53impl<T> From<T> for CommandReply<T> {
54 fn from(result: T) -> Self {
55 Self(result, 0)
56 }
57}
58
59impl<T> From<(T, ValueUnit)> for CommandReply<T> {
60 fn from(value: (T, ValueUnit)) -> Self {
61 Self(value.0, value.1)
62 }
63}
64
65pub fn unknown_input_panic(message: &str, input: &[u8]) -> ! {
66 let mut __input = input;
67 match String::decode(&mut __input) {
68 Ok(s) => panic!("{}: {}", message, s),
69 Err(_) => panic!("{}: {}", message, HexSlice(input)),
70 }
71}
72
73pub struct HexSlice<T: AsRef<[u8]>>(pub T);
74
75impl<T: AsRef<[u8]>> core::fmt::Display for HexSlice<T> {
76 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 let slice = self.0.as_ref();
78 let len = slice.len();
79 let precision = f.precision().unwrap_or(4);
80
81 f.write_str("0x")?;
82 if len <= precision * 2 {
83 for byte in slice {
84 write!(f, "{byte:02x}")?;
85 }
86 } else {
87 for byte in &slice[..precision] {
88 write!(f, "{byte:02x}")?;
89 }
90 f.write_str("..")?;
91 for byte in &slice[len - precision..] {
92 write!(f, "{byte:02x}")?;
93 }
94 }
95 Ok(())
96 }
97}
98
99impl<T: AsRef<[u8]>> core::fmt::Debug for HexSlice<T> {
100 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101 core::fmt::Display::fmt(self, f)
102 }
103}
104
105pub trait InvocationIo: MethodMeta {
112 type Params;
113}
114
115pub fn decode_invocation_params<I>(payload: impl AsRef<[u8]>) -> Result<I::Params>
118where
119 I: InvocationIo,
120 I::Params: Decode,
121{
122 let mut value = payload.as_ref();
123 let header: SailsMessageHeader = Decode::decode(&mut value).map_err(Error::Codec)?;
124 if header.interface_id() != I::INTERFACE_ID {
125 return Err(Error::Rtl(RtlError::InvocationPrefixMismatches));
126 }
127 if header.entry_id() != I::ENTRY_ID {
128 return Err(Error::Rtl(RtlError::InvocationPrefixMismatches));
129 }
130 let value: I::Params = Decode::decode(&mut value).map_err(Error::Codec)?;
131 Ok(value)
132}
133
134pub fn encode_invocation_payload<I, T, R>(value: &T, route_idx: u8, f: impl FnOnce(&[u8]) -> R) -> R
137where
138 I: InvocationIo,
139 T: Encode,
140{
141 encode_invocation_payload_with_id::<T, R>(I::INTERFACE_ID, I::ENTRY_ID, value, route_idx, f)
142}
143
144pub fn encode_invocation_payload_with_id<T, R>(
146 interface_id: InterfaceId,
147 entry_id: u16,
148 value: &T,
149 route_idx: u8,
150 f: impl FnOnce(&[u8]) -> R,
151) -> R
152where
153 T: Encode,
154{
155 let header = SailsMessageHeader::v1(interface_id, entry_id, route_idx);
156 let size = 16 + Encode::encoded_size(value);
157 stack_buffer::with_byte_buffer(size, |buffer| {
158 let mut buffer_writer = MaybeUninitBufferWriter::new(buffer);
159 Encode::encode_to(&header, &mut buffer_writer);
160 Encode::encode_to(value, &mut buffer_writer);
161 buffer_writer.with_buffer(f)
162 })
163}
164
165pub fn with_optimized_encode<T: Encode, R>(
166 value: &T,
167 f: impl FnOnce(&[u8]) -> R,
169) -> R {
170 let size = Encode::encoded_size(value);
171 stack_buffer::with_byte_buffer(size, |buffer| {
172 let mut buffer_writer = MaybeUninitBufferWriter::new(buffer);
173 Encode::encode_to(value, &mut buffer_writer);
174 buffer_writer.with_buffer(f)
175 })
176}
177
178pub fn is_empty_tuple<T: 'static>() -> bool {
179 TypeId::of::<T>() == TypeId::of::<()>()
180}