1use crate::{Error, Limits, Wire};
2use alloc::vec::Vec;
3use core::marker::PhantomData;
4use postcard::ser_flavors::Flavor;
5
6pub(crate) const HEADER: usize = 11;
7
8pub trait Method {
11 type Request: Wire;
13 type Response: Wire;
15 const ID: u64;
17 const NAME: &'static str;
19 const REQUEST_LIMITS: Limits;
21 const RESPONSE_LIMITS: Limits;
23}
24
25macro_rules! retained {
26 ($name:ident) => {
27 pub struct $name<M: Method> {
30 bytes: Vec<u8>,
31 method: PhantomData<fn() -> M>,
32 }
33 impl<M: Method> $name<M> {
34 pub fn as_bytes(&self) -> &[u8] {
36 &self.bytes
37 }
38 pub fn into_bytes(self) -> Vec<u8> {
40 self.bytes
41 }
42 }
43 };
44}
45retained!(RequestBytes);
46retained!(ResponseBytes);
47
48pub(crate) fn admit<T: Wire>(limits: Limits) -> Result<usize, Error> {
49 let shape = T::SHAPE;
50 if [shape.bytes, shape.heap, shape.nodes, shape.depth].contains(&usize::MAX) {
51 return Err(Error::SchemaLimit);
52 }
53 let size = shape.bytes.checked_add(HEADER).ok_or(Error::SchemaLimit)?;
54 let allocation = shape.heap.checked_add(size).ok_or(Error::SchemaLimit)?;
55 if size > limits.bytes
56 || allocation > limits.allocation
57 || shape.nodes > limits.nodes
58 || shape.depth > limits.depth
59 {
60 return Err(Error::SchemaLimit);
61 }
62 Ok(size)
63}
64
65pub(crate) struct Output {
68 pub(crate) bytes: Vec<u8>,
69 pub(crate) limit: usize,
70}
71impl Flavor for Output {
72 type Output = Vec<u8>;
73 fn try_push(&mut self, byte: u8) -> postcard::Result<()> {
74 if self.bytes.len() == self.limit {
75 return Err(postcard::Error::SerializeBufferFull);
76 }
77 self.bytes.push(byte);
78 Ok(())
79 }
80 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
81 if bytes.len() > self.limit - self.bytes.len() {
82 return Err(postcard::Error::SerializeBufferFull);
83 }
84 self.bytes.extend_from_slice(bytes);
85 Ok(())
86 }
87 fn finalize(self) -> postcard::Result<Self::Output> {
88 Ok(self.bytes)
89 }
90}
91
92struct Size {
94 bytes: usize,
95 limit: usize,
96}
97impl Flavor for Size {
98 type Output = usize;
99 fn try_push(&mut self, _: u8) -> postcard::Result<()> {
100 self.try_extend(&[0])
101 }
102 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
103 if bytes.len() > self.limit - self.bytes {
104 return Err(postcard::Error::SerializeBufferFull);
105 }
106 self.bytes += bytes.len();
107 Ok(())
108 }
109 fn finalize(self) -> postcard::Result<usize> {
110 Ok(self.bytes)
111 }
112}
113
114fn encoded_len<T: Wire>(limits: Limits, value: &T) -> Result<usize, Error> {
115 let limit = admit::<T>(limits)?;
116 postcard::serialize_with_flavor(
117 value,
118 Size {
119 bytes: HEADER,
120 limit,
121 },
122 )
123 .map_err(|_| Error::Malformed)
124}
125
126pub(crate) struct Compare<'a> {
129 pub(crate) remaining: &'a [u8],
130 pub(crate) allowance: usize,
131 pub(crate) equal: bool,
132}
133impl Flavor for Compare<'_> {
134 type Output = bool;
135 fn try_push(&mut self, byte: u8) -> postcard::Result<()> {
136 self.try_extend(&[byte])
137 }
138 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
139 if bytes.len() > self.allowance {
140 return Err(postcard::Error::SerializeBufferFull);
141 }
142 self.allowance -= bytes.len();
143 if let Some((prefix, rest)) = self.remaining.split_at_checked(bytes.len()) {
144 self.equal &= prefix == bytes;
145 self.remaining = rest;
146 } else {
147 self.equal = false;
148 self.remaining = &[];
149 }
150 Ok(())
151 }
152 fn finalize(self) -> postcard::Result<Self::Output> {
153 Ok(self.equal && self.remaining.is_empty())
154 }
155}
156
157fn encode<T: Wire>(id: u64, direction: u8, limits: Limits, value: &T) -> Result<Vec<u8>, Error> {
158 let size = admit::<T>(limits)?;
159 let mut bytes = Vec::new();
160 bytes
161 .try_reserve_exact(size)
162 .map_err(|_| Error::Allocation)?;
163 bytes.extend_from_slice(&header(id, direction));
164 postcard::serialize_with_flavor(value, Output { bytes, limit: size })
165 .map_err(|_| Error::Malformed)
166}
167
168fn decode<T: Wire>(id: u64, direction: u8, limits: Limits, bytes: &[u8]) -> Result<T, Error> {
169 let size = admit::<T>(limits)?;
170 if bytes.len() > size || bytes.len() > limits.bytes {
171 return Err(Error::Limit);
172 }
173 let payload = payload(id, direction, bytes)?;
174 let (value, rest) = postcard::take_from_bytes::<T>(payload).map_err(|_| Error::Malformed)?;
175 if !rest.is_empty() {
176 return Err(Error::Trailing);
177 }
178 let equal = postcard::serialize_with_flavor(
179 &value,
180 Compare {
181 remaining: payload,
182 allowance: size - HEADER,
183 equal: true,
184 },
185 )
186 .map_err(|_| Error::Malformed)?;
187 if !equal {
188 return Err(Error::Noncanonical);
189 }
190 Ok(value)
191}
192
193pub fn encode_request<M: Method>(value: &M::Request) -> Result<RequestBytes<M>, Error> {
195 Ok(RequestBytes {
196 bytes: encode(M::ID, 0, M::REQUEST_LIMITS, value)?,
197 method: PhantomData,
198 })
199}
200pub fn encoded_request_len<M: Method>(value: &M::Request) -> Result<usize, Error> {
204 encoded_len(M::REQUEST_LIMITS, value)
205}
206pub fn encoded_response_len<M: Method>(value: &M::Response) -> Result<usize, Error> {
210 encoded_len(M::RESPONSE_LIMITS, value)
211}
212pub fn decode_request<M: Method>(bytes: &[u8]) -> Result<M::Request, Error> {
214 decode(M::ID, 0, M::REQUEST_LIMITS, bytes)
215}
216pub fn encode_response<M: Method>(value: &M::Response) -> Result<ResponseBytes<M>, Error> {
218 Ok(ResponseBytes {
219 bytes: encode(M::ID, 1, M::RESPONSE_LIMITS, value)?,
220 method: PhantomData,
221 })
222}
223pub fn decode_response<M: Method>(bytes: &[u8]) -> Result<M::Response, Error> {
225 decode(M::ID, 1, M::RESPONSE_LIMITS, bytes)
226}
227
228pub(crate) fn header(id: u64, direction: u8) -> [u8; HEADER] {
229 let mut header = [0; HEADER];
230 header[..2].copy_from_slice(b"IW");
231 header[2..10].copy_from_slice(&id.to_le_bytes());
232 header[10] = direction;
233 header
234}
235pub(crate) fn payload(id: u64, direction: u8, bytes: &[u8]) -> Result<&[u8], Error> {
236 if bytes.len() < HEADER {
237 return Err(Error::Malformed);
238 }
239 if &bytes[..2] != b"IW" || bytes[2..10] != id.to_le_bytes() || bytes[10] != direction {
240 return Err(Error::Identity);
241 }
242 Ok(&bytes[HEADER..])
243}