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 size = encoded_len(value, payload_limits(limits, prefix.len())?)?;
91 let mut bytes = Vec::new();
92 bytes
93 .try_reserve_exact(size + prefix.len())
94 .map_err(|_| Error::Allocation)?;
95 bytes.extend_from_slice(prefix);
96 let budget = Budget::new(limits);
97 postcard::serialize_with_flavor(
98 &encode::Bounded {
99 value,
100 budget: &budget,
101 depth: 1,
102 },
103 contract::Output {
104 bytes,
105 limit: size + prefix.len(),
106 },
107 )
108 .map_err(|_| budget.error())
109}
110
111pub fn decode<T: Serialize + DeserializeOwned>(bytes: &[u8], limits: Limits) -> Result<T, Error> {
113 if bytes.len() > limits.bytes {
114 return Err(Error::Limit);
115 }
116 let budget = Budget::new(limits);
117 let mut input = postcard::Deserializer::from_bytes(bytes);
118 let value = T::deserialize(decode::Bounded {
119 inner: &mut input,
120 budget: &budget,
121 depth: 1,
122 })
123 .map_err(|_| budget.error())?;
124 if !input.finalize().map_err(|_| Error::Malformed)?.is_empty() {
125 return Err(Error::Trailing);
126 }
127 let budget = Budget::new(limits);
128 let equal = postcard::serialize_with_flavor(
129 &encode::Bounded {
130 value: &value,
131 budget: &budget,
132 depth: 1,
133 },
134 contract::Compare {
135 remaining: bytes,
136 allowance: limits.bytes,
137 equal: true,
138 },
139 )
140 .map_err(|_| budget.error())?;
141 if !equal {
142 return Err(Error::Noncanonical);
143 }
144 Ok(value)
145}
146
147pub fn encode_request<T: Serialize + ?Sized>(
149 id: u64,
150 value: &T,
151 limits: Limits,
152) -> Result<Vec<u8>, Error> {
153 encode_prefixed(value, limits, &contract::header(id, 0))
154}
155pub fn encode_response<T: Serialize + ?Sized>(
157 id: u64,
158 value: &T,
159 limits: Limits,
160) -> Result<Vec<u8>, Error> {
161 encode_prefixed(value, limits, &contract::header(id, 1))
162}
163pub fn encoded_frame_len<T: Serialize + ?Sized>(value: &T, limits: Limits) -> Result<usize, Error> {
165 encoded_len(value, payload_limits(limits, contract::HEADER)?)
166 .map(|size| size + contract::HEADER)
167}
168pub fn decode_request<T: Serialize + DeserializeOwned>(
170 id: u64,
171 bytes: &[u8],
172 limits: Limits,
173) -> Result<T, Error> {
174 decode_frame(id, 0, bytes, limits)
175}
176pub fn decode_response<T: Serialize + DeserializeOwned>(
178 id: u64,
179 bytes: &[u8],
180 limits: Limits,
181) -> Result<T, Error> {
182 decode_frame(id, 1, bytes, limits)
183}
184fn decode_frame<T: Serialize + DeserializeOwned>(
185 id: u64,
186 direction: u8,
187 bytes: &[u8],
188 limits: Limits,
189) -> Result<T, Error> {
190 if bytes.len() > limits.bytes {
191 return Err(Error::Limit);
192 }
193 let payload = contract::payload(id, direction, bytes)?;
194 decode(payload, payload_limits(limits, contract::HEADER)?)
195}
196
197fn payload_limits(limits: Limits, prefix: usize) -> Result<Limits, Error> {
198 Ok(Limits {
199 bytes: limits.bytes.checked_sub(prefix).ok_or(Error::Limit)?,
200 allocation: limits.allocation.checked_sub(prefix).ok_or(Error::Limit)?,
201 ..limits
202 })
203}