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}
115fn encode_prefixed_into<T: Serialize + ?Sized>(
116 value: &T,
117 limits: Limits,
118 prefix: &[u8],
119 bytes: &mut Vec<u8>,
120) -> Result<(), Error> {
121 bytes.clear();
122 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
123 bytes
124 .try_reserve_exact(size + prefix.len())
125 .map_err(|_| Error::Allocation)?;
126 bytes.extend_from_slice(prefix);
127 let budget = Budget::new(limits);
128 *bytes = postcard::serialize_with_flavor(
129 &encode::Bounded {
130 value,
131 budget: &budget,
132 depth: 1,
133 },
134 contract::Output {
135 bytes: core::mem::take(bytes),
136 limit: size + prefix.len(),
137 },
138 )
139 .map_err(|_| budget.error())?;
140 Ok(())
141}
142
143pub fn encode_request_into<T: Serialize + ?Sized>(
145 id: u64,
146 value: &T,
147 limits: Limits,
148 bytes: &mut Vec<u8>,
149) -> Result<(), Error> {
150 encode_prefixed_into(value, limits, &contract::header(id, 0), bytes)
151}
152
153pub fn encode_response_into<T: Serialize + ?Sized>(
155 id: u64,
156 value: &T,
157 limits: Limits,
158 bytes: &mut Vec<u8>,
159) -> Result<(), Error> {
160 encode_prefixed_into(value, limits, &contract::header(id, 1), bytes)
161}
162
163pub fn decode<'de, T: Deserialize<'de>>(bytes: &'de [u8], limits: Limits) -> Result<T, Error> {
167 if bytes.len() > limits.bytes {
168 return Err(Error::Limit);
169 }
170 let budget = Budget::new(limits);
171 let mut input = parser::Deserializer::from_bytes(bytes);
172 let value = T::deserialize(decode::Bounded {
173 inner: &mut input,
174 budget: &budget,
175 depth: 1,
176 })
177 .map_err(|_| budget.error())?;
178 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
179 return Err(Error::Trailing);
180 }
181 Ok(value)
186}
187
188pub fn encode_request<T: Serialize + ?Sized>(
190 id: u64,
191 value: &T,
192 limits: Limits,
193) -> Result<Vec<u8>, Error> {
194 encode_prefixed(value, limits, &contract::header(id, 0))
195}
196pub fn encode_response<T: Serialize + ?Sized>(
198 id: u64,
199 value: &T,
200 limits: Limits,
201) -> Result<Vec<u8>, Error> {
202 encode_prefixed(value, limits, &contract::header(id, 1))
203}
204pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
206 encoded_len(value, payload_limits(limits, contract::HEADER)?)
207 .map(|size| size + contract::HEADER)
208}
209pub fn decode_request<'de, T: Deserialize<'de>>(
211 id: u64,
212 bytes: &'de [u8],
213 limits: Limits,
214) -> Result<T, Error> {
215 decode_frame(id, 0, bytes, limits)
216}
217pub fn decode_response<'de, T: Deserialize<'de>>(
219 id: u64,
220 bytes: &'de [u8],
221 limits: Limits,
222) -> Result<T, Error> {
223 decode_frame(id, 1, bytes, limits)
224}
225fn decode_frame<'de, T: Deserialize<'de>>(
226 id: u64,
227 direction: u8,
228 bytes: &'de [u8],
229 limits: Limits,
230) -> Result<T, Error> {
231 if bytes.len() > limits.bytes {
232 return Err(Error::Limit);
233 }
234 let payload = contract::payload(id, direction, bytes)?;
235 decode(payload, payload_limits(limits, contract::HEADER)?)
236}
237
238fn payload_limits(limits: Limits, prefix: usize) -> Result<Limits, Error> {
239 Ok(Limits {
240 bytes: limits.bytes.checked_sub(prefix).ok_or(Error::Limit)?,
241 allocation: limits.allocation.checked_sub(prefix).ok_or(Error::Limit)?,
242 ..limits
243 })
244}