1use super::message_future::MessageFutureExtended;
2use crate::{
3 calls::{Action, Remoting},
4 errors::Result,
5 futures::FutureExt,
6 prelude::*,
7};
8use core::future::Future;
9use gstd::{msg, prog};
10
11#[derive(Default)]
12pub struct GStdArgs {
13 wait_up_to: Option<BlockCount>,
14 #[cfg(not(feature = "ethexe"))]
15 reply_deposit: Option<GasUnit>,
16 #[cfg(not(feature = "ethexe"))]
17 reply_hook: Option<Box<dyn FnOnce() + Send + 'static>>,
18 redirect_on_exit: bool,
19}
20
21impl GStdArgs {
22 pub fn with_wait_up_to(self, wait_up_to: Option<BlockCount>) -> Self {
23 Self { wait_up_to, ..self }
24 }
25
26 pub fn with_redirect_on_exit(self, redirect_on_exit: bool) -> Self {
27 Self {
28 redirect_on_exit,
29 ..self
30 }
31 }
32
33 pub fn wait_up_to(&self) -> Option<BlockCount> {
34 self.wait_up_to
35 }
36
37 pub fn redirect_on_exit(&self) -> bool {
38 self.redirect_on_exit
39 }
40}
41
42#[cfg(not(feature = "ethexe"))]
43impl GStdArgs {
44 pub fn with_reply_deposit(self, reply_deposit: Option<GasUnit>) -> Self {
45 Self {
46 reply_deposit,
47 ..self
48 }
49 }
50
51 pub fn with_reply_hook<F: FnOnce() + Send + 'static>(self, f: F) -> Self {
52 Self {
53 reply_hook: Some(Box::new(f)),
54 ..self
55 }
56 }
57
58 pub fn reply_deposit(&self) -> Option<GasUnit> {
59 self.reply_deposit
60 }
61}
62
63#[derive(Debug, Default, Clone)]
64pub struct GStdRemoting;
65
66impl GStdRemoting {
67 pub fn new() -> Self {
68 Self
69 }
70}
71
72impl Remoting for GStdRemoting {
73 type Args = GStdArgs;
74
75 async fn activate(
76 self,
77 code_id: CodeId,
78 salt: impl AsRef<[u8]>,
79 payload: impl AsRef<[u8]>,
80 #[cfg(not(feature = "ethexe"))] gas_limit: Option<GasUnit>,
81 value: ValueUnit,
82 #[allow(unused_variables)] args: GStdArgs,
83 ) -> Result<impl Future<Output = Result<(ActorId, Vec<u8>)>>> {
84 #[cfg(not(feature = "ethexe"))]
85 let mut reply_future = if let Some(gas_limit) = gas_limit {
86 prog::create_program_bytes_with_gas_for_reply(
87 code_id,
88 salt,
89 payload,
90 gas_limit,
91 value,
92 args.reply_deposit.unwrap_or_default(),
93 )?
94 } else {
95 prog::create_program_bytes_for_reply(
96 code_id,
97 salt,
98 payload,
99 value,
100 args.reply_deposit.unwrap_or_default(),
101 )?
102 };
103 #[cfg(feature = "ethexe")]
104 let mut reply_future = prog::create_program_bytes_for_reply(code_id, salt, payload, value)?;
105
106 reply_future = reply_future.up_to(args.wait_up_to)?;
107
108 #[cfg(not(feature = "ethexe"))]
109 if let Some(reply_hook) = args.reply_hook {
110 reply_future = reply_future.handle_reply(reply_hook)?;
111 }
112
113 let reply_future = reply_future.map(|result| result.map_err(Into::into));
114 Ok(reply_future)
115 }
116
117 async fn message(
118 self,
119 target: ActorId,
120 payload: impl AsRef<[u8]>,
121 #[cfg(not(feature = "ethexe"))] gas_limit: Option<GasUnit>,
122 value: ValueUnit,
123 args: GStdArgs,
124 ) -> Result<impl Future<Output = Result<Vec<u8>>>> {
125 let reply_future = send_for_reply(
126 target,
127 payload,
128 #[cfg(not(feature = "ethexe"))]
129 gas_limit,
130 value,
131 args,
132 )?;
133 Ok(reply_future)
134 }
135
136 async fn query(
137 self,
138 target: ActorId,
139 payload: impl AsRef<[u8]>,
140 #[cfg(not(feature = "ethexe"))] gas_limit: Option<GasUnit>,
141 value: ValueUnit,
142 args: GStdArgs,
143 ) -> Result<Vec<u8>> {
144 let reply_future = send_for_reply(
145 target,
146 payload,
147 #[cfg(not(feature = "ethexe"))]
148 gas_limit,
149 value,
150 args,
151 )?;
152 let reply = reply_future.await?;
153 Ok(reply)
154 }
155}
156
157#[cfg(not(feature = "ethexe"))]
158pub(crate) fn send_for_reply_future(
159 target: ActorId,
160 payload: &[u8],
161 gas_limit: Option<GasUnit>,
162 value: ValueUnit,
163 args: GStdArgs,
164) -> Result<msg::MessageFuture> {
165 let mut message_future = if let Some(gas_limit) = gas_limit {
167 msg::send_bytes_with_gas_for_reply(
168 target,
169 payload,
170 gas_limit,
171 value,
172 args.reply_deposit.unwrap_or_default(),
173 )?
174 } else {
175 msg::send_bytes_for_reply(
176 target,
177 payload,
178 value,
179 args.reply_deposit.unwrap_or_default(),
180 )?
181 };
182
183 message_future = message_future.up_to(args.wait_up_to)?;
184
185 if let Some(reply_hook) = args.reply_hook {
186 message_future = message_future.handle_reply(reply_hook)?;
187 }
188 Ok(message_future)
189}
190
191#[cfg(feature = "ethexe")]
192pub(crate) fn send_for_reply_future(
193 target: ActorId,
194 payload: &[u8],
195 value: ValueUnit,
196 args: GStdArgs,
197) -> Result<msg::MessageFuture> {
198 let mut message_future = msg::send_bytes_for_reply(target, payload, value)?;
200
201 message_future = message_future.up_to(args.wait_up_to)?;
202
203 Ok(message_future)
204}
205
206pub(crate) fn send_for_reply<T: AsRef<[u8]>>(
207 target: ActorId,
208 payload: T,
209 #[cfg(not(feature = "ethexe"))] gas_limit: Option<GasUnit>,
210 value: ValueUnit,
211 args: GStdArgs,
212) -> Result<MessageFutureExtended<T>> {
213 #[cfg(not(feature = "ethexe"))]
214 let reply_deposit = args.reply_deposit;
215 let wait_up_to = args.wait_up_to;
216 let redirect_on_exit = args.redirect_on_exit;
217 let message_future = send_for_reply_future(
218 target,
219 payload.as_ref(),
220 #[cfg(not(feature = "ethexe"))]
221 gas_limit,
222 value,
223 args,
224 )?;
225
226 if redirect_on_exit {
227 Ok(MessageFutureExtended::with_redirect(
228 message_future,
229 target,
230 payload,
231 #[cfg(not(feature = "ethexe"))]
232 gas_limit,
233 value,
234 #[cfg(not(feature = "ethexe"))]
235 reply_deposit,
236 wait_up_to,
237 ))
238 } else {
239 Ok(MessageFutureExtended::without_redirect(message_future))
240 }
241}
242
243pub trait WithArgs {
244 fn with_wait_up_to(self, wait_up_to: Option<BlockCount>) -> Self;
245
246 #[cfg(not(feature = "ethexe"))]
247 fn with_reply_deposit(self, reply_deposit: Option<GasUnit>) -> Self;
248
249 #[cfg(not(feature = "ethexe"))]
250 fn with_reply_hook<F: FnOnce() + Send + 'static>(self, f: F) -> Self;
251
252 fn with_redirect_on_exit(self, redirect_on_exit: bool) -> Self;
253}
254
255impl<T> WithArgs for T
256where
257 T: Action<Args = GStdArgs>,
258{
259 fn with_wait_up_to(self, wait_up_to: Option<BlockCount>) -> Self {
260 self.with_args(|args| args.with_wait_up_to(wait_up_to))
261 }
262
263 #[cfg(not(feature = "ethexe"))]
264 fn with_reply_deposit(self, reply_deposit: Option<GasUnit>) -> Self {
265 self.with_args(|args| args.with_reply_deposit(reply_deposit))
266 }
267
268 #[cfg(not(feature = "ethexe"))]
269 fn with_reply_hook<F: FnOnce() + Send + 'static>(self, f: F) -> Self {
270 self.with_args(|args| args.with_reply_hook(f))
271 }
272
273 fn with_redirect_on_exit(self, redirect_on_exit: bool) -> Self {
283 self.with_args(|args| args.with_redirect_on_exit(redirect_on_exit))
284 }
285}