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 encode_request_to_slice<'a, T: Serialize + ?Sized>(
133 id: u64,
134 value: &T,
135 limits: Limits,
136 storage: &'a mut [u8],
137) -> Result<&'a mut [u8], Error> {
138 encode_prefixed_to_slice(value, limits, &contract::header(id, 0), storage)
139}
140
141pub fn encode_response_to_slice<'a, T: Serialize + ?Sized>(
143 id: u64,
144 value: &T,
145 limits: Limits,
146 storage: &'a mut [u8],
147) -> Result<&'a mut [u8], Error> {
148 encode_prefixed_to_slice(value, limits, &contract::header(id, 1), storage)
149}
150
151fn encode_prefixed_to_slice<'a, T: Serialize + ?Sized>(
152 value: &T,
153 limits: Limits,
154 prefix: &[u8],
155 storage: &'a mut [u8],
156) -> Result<&'a mut [u8], Error> {
157 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
158 let output = storage.get_mut(..size + prefix.len()).ok_or(Error::Limit)?;
159 output[..prefix.len()].copy_from_slice(prefix);
160 let budget = Budget::new(limits);
161 let payload = postcard::to_slice(
166 &encode::Bounded {
167 value,
168 budget: &budget,
169 depth: 1,
170 },
171 &mut output[prefix.len()..],
172 )
173 .map_err(|_| budget.error())?;
174 let written = prefix.len() + payload.len();
175 Ok(&mut output[..written])
176}
177
178fn encode_prefixed_into<T: Serialize + ?Sized>(
179 value: &T,
180 limits: Limits,
181 prefix: &[u8],
182 bytes: &mut Vec<u8>,
183) -> Result<(), Error> {
184 bytes.clear();
185 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
186 bytes
187 .try_reserve_exact(size + prefix.len())
188 .map_err(|_| Error::Allocation)?;
189 bytes.extend_from_slice(prefix);
190 let budget = Budget::new(limits);
191 *bytes = postcard::serialize_with_flavor(
192 &encode::Bounded {
193 value,
194 budget: &budget,
195 depth: 1,
196 },
197 contract::Output {
198 bytes: core::mem::take(bytes),
199 limit: size + prefix.len(),
200 },
201 )
202 .map_err(|_| budget.error())?;
203 Ok(())
204}
205
206pub fn encode_request_into<T: Serialize + ?Sized>(
208 id: u64,
209 value: &T,
210 limits: Limits,
211 bytes: &mut Vec<u8>,
212) -> Result<(), Error> {
213 encode_prefixed_into(value, limits, &contract::header(id, 0), bytes)
214}
215
216pub fn encode_response_into<T: Serialize + ?Sized>(
218 id: u64,
219 value: &T,
220 limits: Limits,
221 bytes: &mut Vec<u8>,
222) -> Result<(), Error> {
223 encode_prefixed_into(value, limits, &contract::header(id, 1), bytes)
224}
225
226pub fn decode<'de, T: Deserialize<'de>>(bytes: &'de [u8], limits: Limits) -> Result<T, Error> {
230 if bytes.len() > limits.bytes {
231 return Err(Error::Limit);
232 }
233 let budget = Budget::new(limits);
234 let mut input = parser::Deserializer::from_bytes(bytes);
235 let value = T::deserialize(decode::Bounded {
236 inner: &mut input,
237 budget: &budget,
238 depth: 1,
239 })
240 .map_err(|_| budget.error())?;
241 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
242 return Err(Error::Trailing);
243 }
244 Ok(value)
249}
250
251pub fn encode_request<T: Serialize + ?Sized>(
253 id: u64,
254 value: &T,
255 limits: Limits,
256) -> Result<Vec<u8>, Error> {
257 encode_prefixed(value, limits, &contract::header(id, 0))
258}
259pub fn encode_response<T: Serialize + ?Sized>(
261 id: u64,
262 value: &T,
263 limits: Limits,
264) -> Result<Vec<u8>, Error> {
265 encode_prefixed(value, limits, &contract::header(id, 1))
266}
267pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
269 encoded_len(value, payload_limits(limits, contract::HEADER)?)
270 .map(|size| size + contract::HEADER)
271}
272pub fn decode_request<'de, T: Deserialize<'de>>(
274 id: u64,
275 bytes: &'de [u8],
276 limits: Limits,
277) -> Result<T, Error> {
278 decode_frame(id, 0, bytes, limits)
279}
280pub fn decode_response<'de, T: Deserialize<'de>>(
282 id: u64,
283 bytes: &'de [u8],
284 limits: Limits,
285) -> Result<T, Error> {
286 decode_frame(id, 1, bytes, limits)
287}
288fn decode_frame<'de, T: Deserialize<'de>>(
289 id: u64,
290 direction: u8,
291 bytes: &'de [u8],
292 limits: Limits,
293) -> Result<T, Error> {
294 if bytes.len() > limits.bytes {
295 return Err(Error::Limit);
296 }
297 let payload = contract::payload(id, direction, bytes)?;
298 decode(payload, payload_limits(limits, contract::HEADER)?)
299}
300
301fn payload_limits(limits: Limits, prefix: usize) -> Result<Limits, Error> {
302 Ok(Limits {
303 bytes: limits.bytes.checked_sub(prefix).ok_or(Error::Limit)?,
304 allocation: limits.allocation.checked_sub(prefix).ok_or(Error::Limit)?,
305 ..limits
306 })
307}