air_interpreter_interface/
interpreter_outcome.rs1#[cfg(feature = "marine")]
18use marine_rs_sdk::marine;
19
20#[cfg(feature = "marine")]
21use fluence_it_types::IValue;
22use serde::Deserialize;
23use serde::Serialize;
24
25pub const INTERPRETER_SUCCESS: i64 = 0;
26
27#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct SoftLimitsTriggering {
30 pub air_size_limit_exceeded: bool,
31 pub particle_size_limit_exceeded: bool,
32 pub call_result_size_limit_exceeded: bool,
33}
34
35#[cfg_attr(feature = "marine", marine)]
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct InterpreterOutcome {
39 pub ret_code: i64,
41
42 pub error_message: String,
44
45 pub data: Vec<u8>,
48
49 pub next_peer_pks: Vec<String>,
51
52 pub call_requests: Vec<u8>,
54
55 pub air_size_limit_exceeded: bool,
57
58 pub particle_size_limit_exceeded: bool,
60
61 pub call_result_size_limit_exceeded: bool,
63}
64
65impl SoftLimitsTriggering {
66 pub fn new(
67 air_size_limit_exceeded: bool,
68 particle_size_limit_exceeded: bool,
69 call_result_size_limit_exceeded: bool,
70 ) -> Self {
71 Self {
72 air_size_limit_exceeded,
73 particle_size_limit_exceeded,
74 call_result_size_limit_exceeded,
75 }
76 }
77
78 pub fn are_limits_exceeded(&self) -> bool {
79 self.air_size_limit_exceeded
80 || self.particle_size_limit_exceeded
81 || self.call_result_size_limit_exceeded
82 }
83}
84
85impl InterpreterOutcome {
86 pub fn new(
87 ret_code: i64,
88 error_message: String,
89 data: Vec<u8>,
90 next_peer_pks: Vec<String>,
91 call_requests: SerializedCallRequests,
92 soft_limits_triggering: SoftLimitsTriggering,
93 ) -> Self {
94 let call_requests = call_requests.into();
95 Self {
96 ret_code,
97 error_message,
98 data,
99 next_peer_pks,
100 call_requests,
101 air_size_limit_exceeded: soft_limits_triggering.air_size_limit_exceeded,
102 particle_size_limit_exceeded: soft_limits_triggering.particle_size_limit_exceeded,
103 call_result_size_limit_exceeded: soft_limits_triggering.call_result_size_limit_exceeded,
104 }
105 }
106}
107
108#[cfg(feature = "marine")]
109impl InterpreterOutcome {
110 pub fn from_ivalue(ivalue: IValue) -> Result<Self, String> {
111 const OUTCOME_FIELDS_COUNT: usize = 8;
112
113 let mut record_values = try_as_record(ivalue)?.into_vec();
114 if record_values.len() != OUTCOME_FIELDS_COUNT {
115 return Err(format!(
116 "expected InterpreterOutcome struct with {OUTCOME_FIELDS_COUNT} fields, got {record_values:?}"
117 ));
118 }
119
120 let call_result_size_limit_exceeded = try_as_boolean(
121 record_values.pop().unwrap(),
122 "call_result_size_limit_exceeded",
123 )?;
124 let particle_size_limit_exceeded =
125 try_as_boolean(record_values.pop().unwrap(), "particle_size_limit_exceeded")?;
126 let air_size_limit_exceeded =
127 try_as_boolean(record_values.pop().unwrap(), "air_size_limit_exceeded")?;
128
129 let call_requests = try_as_byte_vec(record_values.pop().unwrap(), "call_requests")?;
130 let next_peer_pks = try_as_string_vec(record_values.pop().unwrap(), "next_peer_pks")?;
131 let data = try_as_byte_vec(record_values.pop().unwrap(), "data")?;
132 let error_message = try_as_string(record_values.pop().unwrap(), "error_message")?;
133 let ret_code = try_as_i64(record_values.pop().unwrap(), "ret_code")?;
134 let soft_limits_triggering = SoftLimitsTriggering::new(
135 air_size_limit_exceeded,
136 particle_size_limit_exceeded,
137 call_result_size_limit_exceeded,
138 );
139
140 let outcome = Self::new(
141 ret_code,
142 error_message,
143 data,
144 next_peer_pks,
145 call_requests.into(),
146 soft_limits_triggering,
147 );
148
149 Ok(outcome)
150 }
151}
152
153#[cfg(feature = "marine")]
154use fluence_it_types::ne_vec::NEVec;
155
156use crate::SerializedCallRequests;
157
158#[cfg(feature = "marine")]
159fn try_as_record(ivalue: IValue) -> Result<NEVec<IValue>, String> {
160 match ivalue {
161 IValue::Record(record_values) => Ok(record_values),
162 v => Err(format!("expected record for InterpreterOutcome, got {v:?}")),
163 }
164}
165
166#[cfg(feature = "marine")]
167fn try_as_i64(ivalue: IValue, field_name: &str) -> Result<i64, String> {
168 match ivalue {
169 IValue::S64(value) => Ok(value),
170 v => Err(format!("expected an i64 for {field_name}, got {v:?}")),
171 }
172}
173
174#[cfg(feature = "marine")]
175pub fn try_as_string(ivalue: IValue, field_name: &str) -> Result<String, String> {
176 match ivalue {
177 IValue::String(value) => Ok(value),
178 v => Err(format!("expected a string for {field_name}, got {v:?}")),
179 }
180}
181
182#[cfg(feature = "marine")]
183fn try_as_byte_vec(ivalue: IValue, field_name: &str) -> Result<Vec<u8>, String> {
184 let byte_vec = match ivalue {
185 IValue::Array(array) => {
186 let array: Result<Vec<_>, _> = array
187 .into_iter()
188 .map(|v| match v {
189 IValue::U8(byte) => Ok(byte),
190 v => Err(format!("expected a byte, got {v:?}")),
191 })
192 .collect();
193 array?
194 }
195 IValue::ByteArray(array) => array,
196 v => return Err(format!("expected a Vec<u8> for {field_name}, got {v:?}")),
197 };
198
199 Ok(byte_vec)
200}
201
202#[cfg(feature = "marine")]
203fn try_as_string_vec(ivalue: IValue, field_name: &str) -> Result<Vec<String>, String> {
204 match ivalue {
205 IValue::Array(ar_values) => {
206 let array = ar_values
207 .into_iter()
208 .map(|v| match v {
209 IValue::String(str) => Ok(str),
210 v => Err(format!("expected string for next_peer_pks, got {v:?}")),
211 })
212 .collect::<Result<Vec<String>, _>>()?;
213
214 Ok(array)
215 }
216 v => Err(format!("expected an array for {field_name}, got {v:?}")),
217 }
218}
219
220#[cfg(feature = "marine")]
221fn try_as_boolean(ivalue: IValue, field_name: &str) -> Result<bool, String> {
222 match ivalue {
223 IValue::Boolean(value) => Ok(value),
224 v => Err(format!("expected a bool for {field_name}, got {v:?}")),
225 }
226}