1#[cfg(test)]
8mod tests;
9
10mod decode;
11mod encode;
12mod parser;
13
14use crate::{Error, Limits, contract};
15use alloc::vec::Vec;
16use core::cell::Cell;
17use serde::{Deserialize, Serialize};
18
19struct Budget {
20 nodes: Cell<usize>,
21 heap_units: Cell<usize>,
22 depth: usize,
23 refused: Cell<bool>,
24}
25impl Budget {
26 fn new(limits: Limits) -> Self {
27 Self {
28 nodes: Cell::new(limits.nodes),
29 heap_units: Cell::new(limits.allocation.saturating_sub(limits.bytes) / 8),
34 depth: limits.depth,
35 refused: Cell::new(limits.allocation < limits.bytes),
36 }
37 }
38 #[cfg_attr(target_arch = "wasm32", inline(always))]
39 fn enter(&self, depth: usize, size: usize) -> bool {
40 self.enter_many(depth, size, 1)
41 }
42 #[cfg_attr(target_arch = "wasm32", inline(always))]
43 fn enter_many(&self, depth: usize, size: usize, count: usize) -> bool {
44 if self.refused.get() {
45 return false;
46 }
47 let Some(nodes) = self.nodes.get().checked_sub(count) else {
48 self.refused.set(true);
49 return false;
50 };
51 if depth > self.depth || !self.bytes(size) {
52 self.refused.set(true);
53 return false;
54 }
55 self.nodes.set(nodes);
56 true
57 }
58 #[cfg_attr(target_arch = "wasm32", inline(always))]
59 fn bytes(&self, bytes: usize) -> bool {
60 let Some(heap) = self.heap_units.get().checked_sub(bytes) else {
61 self.refused.set(true);
62 return false;
63 };
64 self.heap_units.set(heap);
65 true
66 }
67 fn error(&self) -> Error {
68 if self.refused.get() {
69 Error::Limit
70 } else {
71 Error::Malformed
72 }
73 }
74}
75
76pub fn encoded_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
78 let budget = Budget::new(limits);
79 let size = postcard::experimental::serialized_size(&encode::Bounded {
80 value,
81 budget: &budget,
82 depth: 1,
83 })
84 .map_err(|_| budget.error())?;
85 if size > limits.bytes {
86 return Err(Error::Limit);
87 }
88 Ok(size)
89}
90
91pub fn encode<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<Vec<u8>, Error> {
93 encode_prefixed(value, limits, &[])
94}
95fn encode_prefixed<T: Serialize + ?Sized>(
96 value: &T,
97 limits: Limits,
98 prefix: &[u8],
99) -> Result<Vec<u8>, Error> {
100 let mut bytes = Vec::new();
101 encode_prefixed_into(value, limits, prefix, &mut bytes)?;
102 Ok(bytes)
103}
104
105pub fn encode_into<T: Serialize + ?Sized>(
109 value: &T,
110 limits: Limits,
111 bytes: &mut Vec<u8>,
112) -> Result<(), Error> {
113 encode_prefixed_into(value, limits, &[], bytes)
114}
115
116pub fn encode_to_slice<'a, T: Serialize + ?Sized>(
124 value: &T,
125 limits: Limits,
126 storage: &'a mut [u8],
127) -> Result<&'a mut [u8], Error> {
128 encode_prefixed_to_slice(value, limits, &[], storage)
129}
130
131pub fn with_encoded<T: Serialize, R>(
167 value: T,
168 limits: Limits,
169 scratch: &mut [u8],
170 consume: impl FnOnce(&[u8]) -> R,
171) -> Result<R, Error> {
172 let size = encoded_len(&value, limits)?;
173 let budget = Budget::new(limits);
174 let bounded = encode::Bounded {
175 value: &value,
176 budget: &budget,
177 depth: 1,
178 };
179 if let Some(storage) = scratch.get_mut(..size) {
183 let bytes = postcard::to_slice(&bounded, storage).map_err(|_| budget.error())?;
184 drop(value);
185 Ok(consume(bytes))
186 } else {
187 let mut bytes = Vec::new();
188 bytes
189 .try_reserve_exact(size)
190 .map_err(|_| Error::Allocation)?;
191 let bytes =
192 postcard::serialize_with_flavor(&bounded, contract::Output { bytes, limit: size })
193 .map_err(|_| budget.error())?;
194 drop(value);
195 Ok(consume(&bytes))
196 }
197}
198
199pub fn encode_request_to_slice<'a, T: Serialize + ?Sized>(
201 id: u64,
202 value: &T,
203 limits: Limits,
204 storage: &'a mut [u8],
205) -> Result<&'a mut [u8], Error> {
206 encode_prefixed_to_slice(value, limits, &contract::header(id, 0), storage)
207}
208
209pub fn encode_response_to_slice<'a, T: Serialize + ?Sized>(
211 id: u64,
212 value: &T,
213 limits: Limits,
214 storage: &'a mut [u8],
215) -> Result<&'a mut [u8], Error> {
216 encode_prefixed_to_slice(value, limits, &contract::header(id, 1), storage)
217}
218
219fn encode_prefixed_to_slice<'a, T: Serialize + ?Sized>(
220 value: &T,
221 limits: Limits,
222 prefix: &[u8],
223 storage: &'a mut [u8],
224) -> Result<&'a mut [u8], Error> {
225 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
226 let output = storage.get_mut(..size + prefix.len()).ok_or(Error::Limit)?;
227 output[..prefix.len()].copy_from_slice(prefix);
228 let budget = Budget::new(limits);
229 let payload = postcard::to_slice(
234 &encode::Bounded {
235 value,
236 budget: &budget,
237 depth: 1,
238 },
239 &mut output[prefix.len()..],
240 )
241 .map_err(|_| budget.error())?;
242 let written = prefix.len() + payload.len();
243 Ok(&mut output[..written])
244}
245
246fn encode_prefixed_into<T: Serialize + ?Sized>(
247 value: &T,
248 limits: Limits,
249 prefix: &[u8],
250 bytes: &mut Vec<u8>,
251) -> Result<(), Error> {
252 bytes.clear();
253 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
254 bytes
255 .try_reserve_exact(size + prefix.len())
256 .map_err(|_| Error::Allocation)?;
257 bytes.extend_from_slice(prefix);
258 let budget = Budget::new(limits);
259 *bytes = postcard::serialize_with_flavor(
260 &encode::Bounded {
261 value,
262 budget: &budget,
263 depth: 1,
264 },
265 contract::Output {
266 bytes: core::mem::take(bytes),
267 limit: size + prefix.len(),
268 },
269 )
270 .map_err(|_| budget.error())?;
271 Ok(())
272}
273
274pub fn encode_request_into<T: Serialize + ?Sized>(
276 id: u64,
277 value: &T,
278 limits: Limits,
279 bytes: &mut Vec<u8>,
280) -> Result<(), Error> {
281 encode_prefixed_into(value, limits, &contract::header(id, 0), bytes)
282}
283
284pub fn encode_response_into<T: Serialize + ?Sized>(
286 id: u64,
287 value: &T,
288 limits: Limits,
289 bytes: &mut Vec<u8>,
290) -> Result<(), Error> {
291 encode_prefixed_into(value, limits, &contract::header(id, 1), bytes)
292}
293
294pub fn decode<'de, T: Deserialize<'de>>(bytes: &'de [u8], limits: Limits) -> Result<T, Error> {
298 if bytes.len() > limits.bytes {
299 return Err(Error::Limit);
300 }
301 let budget = Budget::new(limits);
302 let mut input = parser::Deserializer::from_bytes(bytes);
303 let value = T::deserialize(decode::Bounded {
304 inner: &mut input,
305 budget: &budget,
306 depth: 1,
307 })
308 .map_err(|_| budget.error())?;
309 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
310 return Err(Error::Trailing);
311 }
312 Ok(value)
317}
318
319pub fn encode_request<T: Serialize + ?Sized>(
321 id: u64,
322 value: &T,
323 limits: Limits,
324) -> Result<Vec<u8>, Error> {
325 encode_prefixed(value, limits, &contract::header(id, 0))
326}
327pub fn encode_response<T: Serialize + ?Sized>(
329 id: u64,
330 value: &T,
331 limits: Limits,
332) -> Result<Vec<u8>, Error> {
333 encode_prefixed(value, limits, &contract::header(id, 1))
334}
335pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
337 encoded_len(value, payload_limits(limits, contract::HEADER)?)
338 .map(|size| size + contract::HEADER)
339}
340pub fn decode_request<'de, T: Deserialize<'de>>(
342 id: u64,
343 bytes: &'de [u8],
344 limits: Limits,
345) -> Result<T, Error> {
346 decode_frame(id, 0, bytes, limits)
347}
348pub fn decode_response<'de, T: Deserialize<'de>>(
350 id: u64,
351 bytes: &'de [u8],
352 limits: Limits,
353) -> Result<T, Error> {
354 decode_frame(id, 1, bytes, limits)
355}
356fn decode_frame<'de, T: Deserialize<'de>>(
357 id: u64,
358 direction: u8,
359 bytes: &'de [u8],
360 limits: Limits,
361) -> Result<T, Error> {
362 if bytes.len() > limits.bytes {
363 return Err(Error::Limit);
364 }
365 let payload = contract::payload(id, direction, bytes)?;
366 decode(payload, payload_limits(limits, contract::HEADER)?)
367}
368
369fn payload_limits(limits: Limits, prefix: usize) -> Result<Limits, Error> {
370 Ok(Limits {
371 bytes: limits.bytes.checked_sub(prefix).ok_or(Error::Limit)?,
372 allocation: limits.allocation.checked_sub(prefix).ok_or(Error::Limit)?,
373 ..limits
374 })
375}