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 self.enter_many(depth, size, 1)
32 }
33 fn enter_many(&self, depth: usize, size: usize, count: usize) -> bool {
34 if self.refused.get() {
35 return false;
36 }
37 let Some(nodes) = self.nodes.get().checked_sub(count) else {
38 self.refused.set(true);
39 return false;
40 };
41 if depth > self.depth || !self.bytes(size) {
42 self.refused.set(true);
43 return false;
44 }
45 self.nodes.set(nodes);
46 true
47 }
48 fn bytes(&self, bytes: usize) -> bool {
49 let Some(cost) = bytes.checked_mul(8) else {
50 self.refused.set(true);
51 return false;
52 };
53 let Some(heap) = self.heap.get().checked_sub(cost) else {
54 self.refused.set(true);
55 return false;
56 };
57 self.heap.set(heap);
58 true
59 }
60 fn error(&self) -> Error {
61 if self.refused.get() {
62 Error::Limit
63 } else {
64 Error::Malformed
65 }
66 }
67}
68
69pub fn encoded_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
71 let budget = Budget::new(limits);
72 let size = postcard::experimental::serialized_size(&encode::Bounded {
73 value,
74 budget: &budget,
75 depth: 1,
76 })
77 .map_err(|_| budget.error())?;
78 if size > limits.bytes {
79 return Err(Error::Limit);
80 }
81 Ok(size)
82}
83
84pub fn encode<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<Vec<u8>, Error> {
86 encode_prefixed(value, limits, &[])
87}
88fn encode_prefixed<T: Serialize + ?Sized>(
89 value: &T,
90 limits: Limits,
91 prefix: &[u8],
92) -> Result<Vec<u8>, Error> {
93 let size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
94 let mut bytes = Vec::new();
95 bytes
96 .try_reserve_exact(size + prefix.len())
97 .map_err(|_| Error::Allocation)?;
98 bytes.extend_from_slice(prefix);
99 let budget = Budget::new(limits);
100 postcard::serialize_with_flavor(
101 &encode::Bounded {
102 value,
103 budget: &budget,
104 depth: 1,
105 },
106 contract::Output {
107 bytes,
108 limit: size + prefix.len(),
109 },
110 )
111 .map_err(|_| budget.error())
112}
113
114pub fn decode<T: Serialize + DeserializeOwned>(bytes: &[u8], limits: Limits) -> Result<T, Error> {
116 if bytes.len() > limits.bytes {
117 return Err(Error::Limit);
118 }
119 let budget = Budget::new(limits);
120 let mut input = postcard::Deserializer::from_bytes(bytes);
121 let value = T::deserialize(decode::Bounded {
122 inner: &mut input,
123 budget: &budget,
124 depth: 1,
125 })
126 .map_err(|_| budget.error())?;
127 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
128 return Err(Error::Trailing);
129 }
130 let budget = Budget::new(limits);
131 let equal = postcard::serialize_with_flavor(
132 &encode::Bounded {
133 value: &value,
134 budget: &budget,
135 depth: 1,
136 },
137 contract::Compare {
138 remaining: bytes,
139 allowance: limits.bytes,
140 equal: true,
141 },
142 )
143 .map_err(|_| budget.error())?;
144 if !equal {
145 return Err(Error::Noncanonical);
146 }
147 Ok(value)
148}
149
150pub fn encode_request<T: Serialize + ?Sized>(
152 id: u64,
153 value: &T,
154 limits: Limits,
155) -> Result<Vec<u8>, Error> {
156 encode_prefixed(value, limits, &contract::header(id, 0))
157}
158pub fn encode_response<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, 1))
165}
166pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
168 encoded_len(value, payload_limits(limits, contract::HEADER)?)
169 .map(|size| size + contract::HEADER)
170}
171pub fn decode_request<T: Serialize + DeserializeOwned>(
173 id: u64,
174 bytes: &[u8],
175 limits: Limits,
176) -> Result<T, Error> {
177 decode_frame(id, 0, bytes, limits)
178}
179pub fn decode_response<T: Serialize + DeserializeOwned>(
181 id: u64,
182 bytes: &[u8],
183 limits: Limits,
184) -> Result<T, Error> {
185 decode_frame(id, 1, bytes, limits)
186}
187fn decode_frame<T: Serialize + DeserializeOwned>(
188 id: u64,
189 direction: u8,
190 bytes: &[u8],
191 limits: Limits,
192) -> Result<T, Error> {
193 if bytes.len() > limits.bytes {
194 return Err(Error::Limit);
195 }
196 let payload = contract::payload(id, direction, bytes)?;
197 decode(payload, payload_limits(limits, contract::HEADER)?)
198}
199
200fn payload_limits(limits: Limits, prefix: usize) -> Result<Limits, Error> {
201 Ok(Limits {
202 bytes: limits.bytes.checked_sub(prefix).ok_or(Error::Limit)?,
203 allocation: limits.allocation.checked_sub(prefix).ok_or(Error::Limit)?,
204 ..limits
205 })
206}