1mod decode;
8mod encode;
9
10use crate::{Error, Limits, contract};
11use alloc::vec::Vec;
12use core::cell::Cell;
13use serde::{Serialize, de::DeserializeOwned};
14
15struct Budget {
16 nodes: Cell<usize>,
17 heap: Cell<usize>,
18 depth: usize,
19 refused: Cell<bool>,
20}
21impl Budget {
22 fn new(limits: Limits) -> Self {
23 Self {
24 nodes: Cell::new(limits.nodes),
25 heap: Cell::new(limits.allocation.saturating_sub(limits.bytes)),
26 depth: limits.depth,
27 refused: Cell::new(limits.allocation < limits.bytes),
28 }
29 }
30 fn enter(&self, depth: usize, size: usize) -> bool {
31 if self.refused.get() {
32 return false;
33 }
34 let Some(nodes) = self.nodes.get().checked_sub(1) else {
35 self.refused.set(true);
36 return false;
37 };
38 if depth > self.depth || !self.bytes(size) {
39 self.refused.set(true);
40 return false;
41 }
42 self.nodes.set(nodes);
43 true
44 }
45 fn bytes(&self, bytes: usize) -> bool {
46 let Some(cost) = bytes.checked_mul(8) else {
47 self.refused.set(true);
48 return false;
49 };
50 let Some(heap) = self.heap.get().checked_sub(cost) else {
51 self.refused.set(true);
52 return false;
53 };
54 self.heap.set(heap);
55 true
56 }
57 fn error(&self) -> Error {
58 if self.refused.get() {
59 Error::Limit
60 } else {
61 Error::Malformed
62 }
63 }
64}
65
66pub fn encoded_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
68 let budget = Budget::new(limits);
69 let size = postcard::experimental::serialized_size(&encode::Bounded {
70 value,
71 budget: &budget,
72 depth: 1,
73 })
74 .map_err(|_| budget.error())?;
75 if size > limits.bytes {
76 return Err(Error::Limit);
77 }
78 Ok(size)
79}
80
81pub fn encode<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<Vec<u8>, Error> {
83 encode_prefixed(value, limits, &[])
84}
85fn encode_prefixed<T: Serialize + ?Sized>(
86 value: &T,
87 limits: Limits,
88 prefix: &[u8],
89) -> Result<Vec<u8>, Error> {
90 let payload_limit = limits.bytes.checked_sub(prefix.len()).ok_or(Error::Limit)?;
91 let size = encoded_len(
92 value,
93 Limits {
94 bytes: payload_limit,
95 allocation: limits
96 .allocation
97 .checked_sub(prefix.len())
98 .ok_or(Error::Limit)?,
99 ..limits
100 },
101 )?;
102 let mut bytes = Vec::new();
103 bytes
104 .try_reserve_exact(size + prefix.len())
105 .map_err(|_| Error::Allocation)?;
106 bytes.extend_from_slice(prefix);
107 let budget = Budget::new(limits);
108 postcard::serialize_with_flavor(
109 &encode::Bounded {
110 value,
111 budget: &budget,
112 depth: 1,
113 },
114 contract::Output {
115 bytes,
116 limit: size + prefix.len(),
117 },
118 )
119 .map_err(|_| budget.error())
120}
121
122pub fn decode<T: Serialize + DeserializeOwned>(bytes: &[u8], limits: Limits) -> Result<T, Error> {
124 if bytes.len() > limits.bytes {
125 return Err(Error::Limit);
126 }
127 let budget = Budget::new(limits);
128 let mut input = postcard::Deserializer::from_bytes(bytes);
129 let value = T::deserialize(decode::Bounded {
130 inner: &mut input,
131 budget: &budget,
132 depth: 1,
133 })
134 .map_err(|_| budget.error())?;
135 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
136 return Err(Error::Trailing);
137 }
138 let budget = Budget::new(limits);
139 let equal = postcard::serialize_with_flavor(
140 &encode::Bounded {
141 value: &value,
142 budget: &budget,
143 depth: 1,
144 },
145 contract::Compare {
146 remaining: bytes,
147 allowance: limits.bytes,
148 equal: true,
149 },
150 )
151 .map_err(|_| budget.error())?;
152 if !equal {
153 return Err(Error::Noncanonical);
154 }
155 Ok(value)
156}
157
158pub fn encode_request<T: Serialize + ?Sized>(
160 id: u64,
161 value: &T,
162 limits: Limits,
163) -> Result<Vec<u8>, Error> {
164 encode_prefixed(value, limits, &contract::header(id, 0))
165}
166pub fn encode_response<T: Serialize + ?Sized>(
168 id: u64,
169 value: &T,
170 limits: Limits,
171) -> Result<Vec<u8>, Error> {
172 encode_prefixed(value, limits, &contract::header(id, 1))
173}
174pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
176 let bytes = limits
177 .bytes
178 .checked_sub(contract::HEADER)
179 .ok_or(Error::Limit)?;
180 encoded_len(
181 value,
182 Limits {
183 bytes,
184 allocation: limits
185 .allocation
186 .checked_sub(contract::HEADER)
187 .ok_or(Error::Limit)?,
188 ..limits
189 },
190 )
191 .map(|size| size + contract::HEADER)
192}
193pub fn decode_request<T: Serialize + DeserializeOwned>(
195 id: u64,
196 bytes: &[u8],
197 limits: Limits,
198) -> Result<T, Error> {
199 decode_frame(id, 0, bytes, limits)
200}
201pub fn decode_response<T: Serialize + DeserializeOwned>(
203 id: u64,
204 bytes: &[u8],
205 limits: Limits,
206) -> Result<T, Error> {
207 decode_frame(id, 1, bytes, limits)
208}
209fn decode_frame<T: Serialize + DeserializeOwned>(
210 id: u64,
211 direction: u8,
212 bytes: &[u8],
213 limits: Limits,
214) -> Result<T, Error> {
215 if bytes.len() > limits.bytes {
216 return Err(Error::Limit);
217 }
218 let payload = contract::payload(id, direction, bytes)?;
219 decode(
220 payload,
221 Limits {
222 bytes: limits.bytes - contract::HEADER,
223 allocation: limits
224 .allocation
225 .checked_sub(contract::HEADER)
226 .ok_or(Error::Limit)?,
227 ..limits
228 },
229 )
230}