1#[cfg(test)]
2mod tests;
3
4use crate::{Error, Limits, Wire};
5use alloc::vec::Vec;
6use core::{cell::Cell, marker::PhantomData};
7use postcard::ser_flavors::Flavor;
8
9pub(crate) const HEADER: usize = 11;
10
11pub trait Method {
14 type Request: Wire;
17 type Response: Wire;
19 const ID: u64;
21 const NAME: &'static str;
23 const REQUEST_LIMITS: Limits;
25 const RESPONSE_LIMITS: Limits;
27}
28
29macro_rules! retained {
30 ($name:ident) => {
31 pub struct $name<M: Method> {
34 bytes: Vec<u8>,
35 method: PhantomData<fn() -> M>,
36 }
37 impl<M: Method> $name<M> {
38 pub fn as_bytes(&self) -> &[u8] {
40 &self.bytes
41 }
42 pub fn into_bytes(self) -> Vec<u8> {
44 self.bytes
45 }
46 }
47 };
48}
49retained!(RequestBytes);
50retained!(ResponseBytes);
51
52pub(crate) fn admit<T: Wire>(limits: Limits) -> Result<usize, Error> {
53 let shape = T::SHAPE;
54 if [shape.bytes, shape.heap, shape.nodes, shape.depth].contains(&usize::MAX) {
55 return Err(Error::SchemaLimit);
56 }
57 let size = shape.bytes.checked_add(HEADER).ok_or(Error::SchemaLimit)?;
58 let allocation = shape.heap.checked_add(size).ok_or(Error::SchemaLimit)?;
59 if size > limits.bytes
60 || allocation > limits.allocation
61 || shape.nodes > limits.nodes
62 || shape.depth > limits.depth
63 {
64 return Err(Error::SchemaLimit);
65 }
66 Ok(size)
67}
68
69pub(crate) struct Output {
72 pub(crate) bytes: Vec<u8>,
73 pub(crate) limit: usize,
74}
75impl Flavor for Output {
76 type Output = Vec<u8>;
77 fn try_push(&mut self, byte: u8) -> postcard::Result<()> {
78 if self.bytes.len() == self.limit {
79 return Err(postcard::Error::SerializeBufferFull);
80 }
81 self.bytes.push(byte);
82 Ok(())
83 }
84 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
85 if bytes.len() > self.limit - self.bytes.len() {
86 return Err(postcard::Error::SerializeBufferFull);
87 }
88 self.bytes.extend_from_slice(bytes);
89 Ok(())
90 }
91 fn finalize(self) -> postcard::Result<Self::Output> {
92 Ok(self.bytes)
93 }
94}
95
96struct GrowingOutput<'a> {
99 output: Output,
100 allocation_failed: &'a Cell<bool>,
101}
102impl GrowingOutput<'_> {
103 #[cold]
104 #[inline(never)]
105 fn reserve(&mut self, additional: usize) -> postcard::Result<()> {
106 let bytes = &mut self.output.bytes;
107 if additional > self.output.limit - bytes.len() {
108 return Err(postcard::Error::SerializeBufferFull);
109 }
110 let required = bytes.len() + additional;
111 if required > bytes.capacity() {
112 let capacity = if required > self.output.limit / 4 {
115 self.output.limit
116 } else {
117 required
118 .max(bytes.capacity().saturating_mul(2).max(64))
119 .min(self.output.limit)
120 };
121 bytes
122 .try_reserve_exact(capacity - bytes.len())
123 .map_err(|_| {
124 self.allocation_failed.set(true);
125 postcard::Error::SerializeBufferFull
126 })?;
127 }
128 Ok(())
129 }
130}
131impl Flavor for GrowingOutput<'_> {
132 type Output = Vec<u8>;
133 #[inline(always)]
134 fn try_push(&mut self, byte: u8) -> postcard::Result<()> {
135 if self.output.bytes.len() == self.output.limit {
136 return Err(postcard::Error::SerializeBufferFull);
137 }
138 if self.output.bytes.len() == self.output.bytes.capacity() {
139 self.reserve(1)?;
140 }
141 self.output.bytes.push(byte);
142 Ok(())
143 }
144 #[inline(always)]
145 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
146 if bytes.len() > self.output.limit - self.output.bytes.len() {
147 return Err(postcard::Error::SerializeBufferFull);
148 }
149 if bytes.len() > self.output.bytes.capacity() - self.output.bytes.len() {
150 self.reserve(bytes.len())?;
151 }
152 self.output.bytes.extend_from_slice(bytes);
153 Ok(())
154 }
155 fn finalize(self) -> postcard::Result<Self::Output> {
156 Ok(self.output.bytes)
157 }
158}
159
160struct Size {
162 bytes: usize,
163 limit: usize,
164}
165impl Flavor for Size {
166 type Output = usize;
167 fn try_push(&mut self, _: u8) -> postcard::Result<()> {
168 self.try_extend(&[0])
169 }
170 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
171 if bytes.len() > self.limit - self.bytes {
172 return Err(postcard::Error::SerializeBufferFull);
173 }
174 self.bytes += bytes.len();
175 Ok(())
176 }
177 fn finalize(self) -> postcard::Result<usize> {
178 Ok(self.bytes)
179 }
180}
181
182fn encoded_len<T: Wire>(limits: Limits, value: &T) -> Result<usize, Error> {
183 let limit = admit::<T>(limits)?;
184 postcard::serialize_with_flavor(
185 value,
186 Size {
187 bytes: HEADER,
188 limit,
189 },
190 )
191 .map_err(|_| Error::Malformed)
192}
193
194pub(crate) struct Compare<'a> {
197 pub(crate) remaining: &'a [u8],
198 pub(crate) allowance: usize,
199 pub(crate) equal: bool,
200}
201impl Flavor for Compare<'_> {
202 type Output = bool;
203 #[inline(always)]
204 fn try_push(&mut self, byte: u8) -> postcard::Result<()> {
205 if self.allowance == 0 {
206 return Err(postcard::Error::SerializeBufferFull);
207 }
208 self.allowance -= 1;
209 if let Some((first, rest)) = self.remaining.split_first() {
210 self.equal &= *first == byte;
211 self.remaining = rest;
212 } else {
213 self.equal = false;
214 }
215 Ok(())
216 }
217 fn try_extend(&mut self, bytes: &[u8]) -> postcard::Result<()> {
218 if let [byte] = bytes {
219 return self.try_push(*byte);
220 }
221 if bytes.len() > self.allowance {
222 return Err(postcard::Error::SerializeBufferFull);
223 }
224 self.allowance -= bytes.len();
225 if let Some((prefix, rest)) = self.remaining.split_at_checked(bytes.len()) {
226 self.equal &= if core::ptr::eq(prefix.as_ptr(), bytes.as_ptr()) {
230 true
234 } else if cfg!(any(target_arch = "wasm32", test)) && bytes.len() >= 8 {
235 if bytes.len() >= 64 {
241 equal_bulk(prefix, bytes)
242 } else {
243 let (left, left_tail) = prefix.as_chunks::<8>();
244 let (right, right_tail) = bytes.as_chunks::<8>();
245 left.iter().zip(right).fold(0_u64, |difference, (a, b)| {
246 difference | (u64::from_ne_bytes(*a) ^ u64::from_ne_bytes(*b))
247 }) == 0
248 && left_tail == right_tail
249 }
250 } else {
251 prefix == bytes
252 };
253 self.remaining = rest;
254 } else {
255 self.equal = false;
256 self.remaining = &[];
257 }
258 Ok(())
259 }
260 fn finalize(self) -> postcard::Result<Self::Output> {
261 Ok(self.equal && self.remaining.is_empty())
262 }
263}
264
265#[doc(hidden)]
272pub struct Canonical<'a> {
273 compare: Compare<'a>,
274}
275impl Canonical<'_> {
276 pub fn compare<T: serde::Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
278 let mut serializer = postcard::Serializer {
279 output: Compare {
280 remaining: self.compare.remaining,
281 allowance: self.compare.allowance,
282 equal: self.compare.equal,
283 },
284 };
285 value
286 .serialize(&mut serializer)
287 .map_err(|_| Error::Malformed)?;
288 self.compare = serializer.output;
289 Ok(())
290 }
291 pub(crate) fn copied_bytes(&mut self, length: usize) -> Result<(), Error> {
293 self.compare(&length)?;
294 if length > self.compare.allowance {
295 return Err(Error::Malformed);
296 }
297 self.compare.allowance -= length;
298 if let Some(rest) = self.compare.remaining.get(length..) {
299 self.compare.remaining = rest;
300 } else {
301 self.compare.equal = false;
302 self.compare.remaining = &[];
303 }
304 Ok(())
305 }
306}
307
308#[inline(never)]
311fn equal_bulk(prefix: &[u8], bytes: &[u8]) -> bool {
312 let (left, left_tail) = prefix.as_chunks::<64>();
313 let (right, right_tail) = bytes.as_chunks::<64>();
314 left.iter().zip(right).fold(0_u128, |difference, (a, b)| {
315 let (a, _) = a.as_chunks::<16>();
316 let (b, _) = b.as_chunks::<16>();
317 difference
318 | (u128::from_ne_bytes(a[0]) ^ u128::from_ne_bytes(b[0]))
319 | (u128::from_ne_bytes(a[1]) ^ u128::from_ne_bytes(b[1]))
320 | (u128::from_ne_bytes(a[2]) ^ u128::from_ne_bytes(b[2]))
321 | (u128::from_ne_bytes(a[3]) ^ u128::from_ne_bytes(b[3]))
322 }) == 0
323 && {
324 let (left, left_tail) = left_tail.as_chunks::<8>();
325 let (right, right_tail) = right_tail.as_chunks::<8>();
326 left.iter().zip(right).fold(0_u64, |difference, (a, b)| {
327 difference | (u64::from_ne_bytes(*a) ^ u64::from_ne_bytes(*b))
328 }) == 0
329 && left_tail == right_tail
330 }
331}
332
333#[cfg_attr(target_arch = "wasm32", inline(never))]
335fn fresh_output(id: u64, direction: u8, size: usize) -> Result<Output, Error> {
336 let mut bytes = Vec::new();
339 bytes
340 .try_reserve_exact(if size <= 128 { size } else { 64 })
341 .map_err(|_| Error::Allocation)?;
342 bytes.extend_from_slice(&header(id, direction));
343 Ok(Output { bytes, limit: size })
344}
345
346fn encode<T: Wire>(id: u64, direction: u8, limits: Limits, value: &T) -> Result<Vec<u8>, Error> {
347 let size = admit::<T>(limits)?;
348 let output = fresh_output(id, direction, size)?;
349 let allocation_failed = Cell::new(false);
350 let output = GrowingOutput {
351 output,
352 allocation_failed: &allocation_failed,
353 };
354 postcard::serialize_with_flavor(value, output).map_err(|_| {
355 if allocation_failed.get() {
356 Error::Allocation
357 } else {
358 Error::Malformed
359 }
360 })
361}
362
363fn encode_into<T: Wire>(
366 id: u64,
367 direction: u8,
368 limits: Limits,
369 value: &T,
370 bytes: &mut Vec<u8>,
371) -> Result<(), Error> {
372 bytes.clear();
373 let size = admit::<T>(limits)?;
374 bytes
377 .try_reserve_exact(size.min(64))
378 .map_err(|_| Error::Allocation)?;
379 bytes.extend_from_slice(&header(id, direction));
380 let allocation_failed = Cell::new(false);
381 let output = GrowingOutput {
382 output: Output {
383 bytes: core::mem::take(bytes),
384 limit: size,
385 },
386 allocation_failed: &allocation_failed,
387 };
388 *bytes = postcard::serialize_with_flavor(value, output).map_err(|_| {
389 if allocation_failed.get() {
390 Error::Allocation
391 } else {
392 Error::Malformed
393 }
394 })?;
395 Ok(())
396}
397
398fn decode<'de, T: Wire + serde::Deserialize<'de>>(
399 id: u64,
400 direction: u8,
401 limits: Limits,
402 bytes: &'de [u8],
403) -> Result<T, Error> {
404 let size = admit::<T>(limits)?;
405 if bytes.len() > size {
407 return Err(Error::Limit);
408 }
409 let payload = payload(id, direction, bytes)?;
410 let (value, rest) = postcard::take_from_bytes::<T>(payload).map_err(|_| Error::Malformed)?;
411 if !rest.is_empty() {
412 return Err(Error::Trailing);
413 }
414 let mut canonical = Canonical {
415 compare: Compare {
416 remaining: payload,
417 allowance: size - HEADER,
418 equal: true,
419 },
420 };
421 value.__canonical(&mut canonical)?;
422 let equal = canonical.compare.finalize().map_err(|_| Error::Malformed)?;
423 if !equal {
424 return Err(Error::Noncanonical);
425 }
426 Ok(value)
427}
428
429pub fn encode_request<M: Method>(value: &M::Request) -> Result<RequestBytes<M>, Error> {
431 Ok(RequestBytes {
432 bytes: encode(M::ID, 0, M::REQUEST_LIMITS, value)?,
433 method: PhantomData,
434 })
435}
436pub fn encode_request_into<M: Method>(
442 value: &M::Request,
443 bytes: &mut Vec<u8>,
444) -> Result<(), Error> {
445 encode_into(M::ID, 0, M::REQUEST_LIMITS, value, bytes)
446}
447
448pub fn encode_response_into<M: Method>(
453 value: &M::Response,
454 bytes: &mut Vec<u8>,
455) -> Result<(), Error> {
456 encode_into(M::ID, 1, M::RESPONSE_LIMITS, value, bytes)
457}
458
459pub fn encoded_request_len<M: Method>(value: &M::Request) -> Result<usize, Error> {
463 encoded_len(M::REQUEST_LIMITS, value)
464}
465pub fn encoded_response_len<M: Method>(value: &M::Response) -> Result<usize, Error> {
469 encoded_len(M::RESPONSE_LIMITS, value)
470}
471pub fn decode_request<'de, M: Method>(bytes: &'de [u8]) -> Result<M::Request, Error>
473where
474 M::Request: serde::Deserialize<'de>,
475{
476 decode(M::ID, 0, M::REQUEST_LIMITS, bytes)
477}
478pub fn encode_response<M: Method>(value: &M::Response) -> Result<ResponseBytes<M>, Error> {
480 Ok(ResponseBytes {
481 bytes: encode(M::ID, 1, M::RESPONSE_LIMITS, value)?,
482 method: PhantomData,
483 })
484}
485pub fn decode_response<'de, M: Method>(bytes: &'de [u8]) -> Result<M::Response, Error>
487where
488 M::Response: serde::Deserialize<'de>,
489{
490 decode(M::ID, 1, M::RESPONSE_LIMITS, bytes)
491}
492
493pub(crate) fn header(id: u64, direction: u8) -> [u8; HEADER] {
494 let mut header = [0; HEADER];
495 header[..2].copy_from_slice(b"IW");
496 header[2..10].copy_from_slice(&id.to_le_bytes());
497 header[10] = direction;
498 header
499}
500#[cfg_attr(target_arch = "wasm32", inline(never))]
502pub(crate) fn payload(id: u64, direction: u8, bytes: &[u8]) -> Result<&[u8], Error> {
503 if bytes.len() < HEADER {
504 return Err(Error::Malformed);
505 }
506 if &bytes[..2] != b"IW" || bytes[2..10] != id.to_le_bytes() || bytes[10] != direction {
507 return Err(Error::Identity);
508 }
509 Ok(&bytes[HEADER..])
510}