ab_contracts_common/
env.rs1use crate::ContractError;
2use crate::method::{ExternalArgs, MethodFingerprint};
3use ab_core_primitives::address::Address;
4use ab_core_primitives::shard::ShardIndex;
5use ab_io_type::trivial_type::TrivialType;
6use core::ffi::c_void;
7use core::marker::PhantomData;
8use core::ptr::NonNull;
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
21#[repr(u8)]
22pub enum MethodContext {
23 Keep,
25 Reset,
27 Replace,
29}
30
31#[derive(Debug)]
33#[repr(C)]
34#[must_use]
35pub struct PreparedMethod<'a> {
36 pub contract: Address,
38 pub fingerprint: MethodFingerprint,
40 pub external_args: NonNull<NonNull<c_void>>,
43 pub method_context: MethodContext,
45 pub phantom: PhantomData<&'a ()>,
47}
48
49#[cfg(feature = "guest")]
50unsafe extern "C" {
51 fn __ab_host_call_import(method: *const PreparedMethod<'_>) -> crate::ExitCode;
53}
54
55#[cfg(feature = "guest")]
59#[unsafe(no_mangle)]
60#[inline(never)]
61#[doc(hidden)]
62pub extern "C" fn __ab_host_call(method: &PreparedMethod<'_>) -> crate::ExitCode {
63 unsafe { __ab_host_call_import(method) }
65}
66
67#[derive(Debug, Copy, Clone, TrivialType)]
69#[repr(C)]
70pub struct EnvState {
71 pub shard_index: ShardIndex,
73 pub padding_0: [u8; 4],
75 pub own_address: Address,
77 pub context: Address,
79 pub caller: Address,
81}
82
83#[cfg(feature = "executor")]
85pub trait ExecutorContext: core::fmt::Debug {
86 fn call(
88 &self,
89 previous_env_state: &EnvState,
90 prepared_methods: &mut PreparedMethod<'_>,
91 ) -> Result<(), ContractError>;
92}
93
94#[cfg(all(feature = "executor", feature = "guest", not(any(doc, unix, windows))))]
95compile_error!(
96 "`executor` and `guest` features are mutually exclusive due to it affecting `Env` layout"
97);
98
99#[derive(Debug)]
104#[repr(C)]
105pub struct Env<'a> {
106 state: EnvState,
107 #[cfg(feature = "executor")]
108 executor_context: &'a mut dyn ExecutorContext,
109 phantom_data: PhantomData<&'a ()>,
110}
111
112impl<'a> Env<'a> {
116 #[cfg(feature = "executor")]
118 #[inline(always)]
119 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
120 pub fn with_executor_context(
121 state: EnvState,
122 executor_context: &'a mut dyn ExecutorContext,
123 ) -> Self {
124 Self {
125 state,
126 executor_context,
127 phantom_data: PhantomData,
128 }
129 }
130
131 #[cfg(feature = "executor")]
133 #[inline(always)]
134 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
135 pub fn get_mut_executor_context(&mut self) -> &mut dyn ExecutorContext {
136 self.executor_context
137 }
138
139 #[inline(always)]
141 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
142 pub fn shard_index(&self) -> ShardIndex {
143 self.state.shard_index
144 }
145
146 #[inline(always)]
148 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
149 pub fn own_address(&self) -> Address {
150 self.state.own_address
151 }
152
153 #[inline(always)]
155 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
156 pub fn context<'b>(self: &'b &'b mut Self) -> Address {
157 self.state.context
158 }
159
160 #[inline(always)]
162 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
163 pub fn caller<'b>(self: &'b &'b mut Self) -> Address {
164 self.state.caller
165 }
166
167 #[inline(always)]
171 pub fn call<Args>(
172 &self,
173 contract: Address,
174 args: &mut Args,
175 method_context: MethodContext,
176 ) -> Result<(), ContractError>
177 where
178 Args: ExternalArgs,
179 {
180 let prepared_method = Self::prepare_method_call(contract, args, method_context);
181 self.call_prepared(prepared_method)
182 }
183
184 #[inline(always)]
188 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
189 pub fn prepare_method_call<Args>(
190 contract: Address,
191 args: &mut Args,
192 method_context: MethodContext,
193 ) -> PreparedMethod<'_>
194 where
195 Args: ExternalArgs,
196 {
197 PreparedMethod {
198 contract,
199 fingerprint: Args::FINGERPRINT,
200 external_args: NonNull::from_mut(args).cast::<NonNull<c_void>>(),
202 method_context,
203 phantom: PhantomData,
204 }
205 }
206
207 #[inline]
212 pub fn call_prepared(&self, method: PreparedMethod<'_>) -> Result<(), ContractError> {
213 #[cfg(feature = "executor")]
214 {
215 let mut method = method;
216 self.executor_context.call(&self.state, &mut method)
217 }
218 #[cfg(all(feature = "guest", not(feature = "executor")))]
219 {
220 __ab_host_call(&method).into()
221 }
222 #[cfg(not(any(feature = "executor", feature = "guest")))]
223 {
224 let _ = method;
225 Err(ContractError::InternalError)
226 }
227 }
228}