peek_poke/
lib.rs

1// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Fast binary serialization and deserialization for types with a known maximum size.
12//!
13//! ## Binary Encoding Scheme
14//!
15//! ## Usage
16//!
17//! ## Comparison to bincode
18
19#[cfg(feature = "derive")]
20pub use peek_poke_derive::*;
21
22use core::{marker::PhantomData, mem::size_of, slice};
23use crate::{slice_ext::*, vec_ext::*};
24
25mod slice_ext;
26mod vec_ext;
27
28union MaybeUninitShim<T: Copy> {
29    uninit: (),
30    init: T,
31}
32
33/// Peek helper for constructing a `T` by `Copy`ing into an uninitialized stack
34/// allocation.
35pub unsafe fn peek_from_uninit<T: Copy + Peek>(bytes: *const u8) -> (T, *const u8) {
36    let mut val = MaybeUninitShim { uninit: () };
37    let bytes = <T>::peek_from(bytes, &mut val.init);
38    (val.init, bytes)
39}
40
41/// Peek helper for constructing a `T` by `Default` initialized stack
42/// allocation.
43pub unsafe fn peek_from_default<T: Default + Peek>(bytes: *const u8) -> (T, *const u8) {
44    let mut val = T::default();
45    let bytes = <T>::peek_from(bytes, &mut val);
46    (val, bytes)
47}
48
49/// Peek inplace a `T` from a slice of bytes, returning a slice of the remaining
50/// bytes. `src` must contain at least `T::max_size()` bytes.
51///
52/// [`ensure_red_zone`] can be used to add required padding.
53pub fn peek_from_slice<'a, T: Peek>(src: &'a [u8], dst: &mut T) -> &'a [u8] {
54    unsafe {
55        // If src.len() == T::max_size() then src is at the start of the red-zone.
56        assert!(T::max_size() < src.len(), "WRDL: unexpected end of display list");
57        let end_ptr = T::peek_from(src.as_ptr(), dst);
58        let len = end_ptr as usize - src.as_ptr() as usize;
59        // Did someone break the T::peek_from() can't read more than T::max_size()
60        // bytes contract?
61        assert!(len <= src.len(), "WRDL: Peek::max_size was wrong");
62        slice::from_raw_parts(end_ptr, src.len() - len)
63    }
64}
65
66/// Poke helper to insert a serialized version of `src` at the beginning for `dst`.
67pub fn poke_inplace_slice<T: Poke>(src: &T, dst: &mut [u8]) {
68    assert!(T::max_size() <= dst.len(),  "WRDL: buffer too small to write into");
69    unsafe {
70        src.poke_into(dst.as_mut_ptr());
71    }
72}
73
74/// Poke helper to append a serialized version of `src` to the end of `dst`.
75pub fn poke_into_vec<T: Poke>(src: &T, dst: &mut Vec<u8>) {
76    dst.reserve(T::max_size());
77    unsafe {
78        let ptr = dst.as_end_mut_ptr();
79        let end_ptr = src.poke_into(ptr);
80        dst.set_end_ptr(end_ptr);
81    }
82}
83
84// TODO: Is returning the len of the iterator of any practical use?
85pub fn poke_extend_vec<I>(src: I, dst: &mut Vec<u8>) -> usize
86where
87    I: ExactSizeIterator,
88    I::Item: Poke,
89{
90    let len = src.len();
91    let max_size = len * I::Item::max_size();
92    dst.reserve(max_size);
93    unsafe {
94        let ptr = dst.as_end_mut_ptr();
95        // Guard against the possibility of a misbehaved implementation of
96        // ExactSizeIterator by writing at most `len` items.
97        let end_ptr = src.take(len).fold(ptr, |ptr, item| item.poke_into(ptr));
98        dst.set_end_ptr(end_ptr);
99    }
100
101    len
102}
103
104/// Add `T::max_size()` "red zone" (padding of zeroes) to the end of the vec of
105/// `bytes`. This allows deserialization to assert that at least `T::max_size()`
106/// bytes exist at all times.
107pub fn ensure_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
108    bytes.reserve(T::max_size());
109    unsafe {
110        let end_ptr = bytes.as_end_mut_ptr();
111        end_ptr.write_bytes(0, T::max_size());
112        bytes.set_end_ptr(end_ptr.add(T::max_size()));
113    }
114}
115
116#[inline]
117unsafe fn read_verbatim<T>(src: *const u8, dst: *mut T) -> *const u8 {
118    *dst = (src as *const T).read_unaligned();
119    src.add(size_of::<T>())
120}
121
122#[inline]
123unsafe fn write_verbatim<T>(src: T, dst: *mut u8) -> *mut u8 {
124    (dst as *mut T).write_unaligned(src);
125    dst.add(size_of::<T>())
126}
127
128#[cfg(feature = "extras")]
129mod euclid;
130
131/// A trait for values that provide serialization into buffers of bytes.
132///
133/// # Example
134///
135/// ```no_run
136/// use peek_poke::Poke;
137///
138/// struct Bar {
139///     a: u32,
140///     b: u8,
141///     c: i16,
142/// }
143///
144/// unsafe impl Poke for Bar {
145///     fn max_size() -> usize {
146///         <u32>::max_size() + <u8>::max_size() + <i16>::max_size()
147///     }
148///     unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
149///         let bytes = self.a.poke_into(bytes);
150///         let bytes = self.b.poke_into(bytes);
151///         self.c.poke_into(bytes)
152///     }
153/// }
154/// ```
155///
156/// # Safety
157///
158/// The `Poke` trait is an `unsafe` trait for the reasons, and implementors must
159/// ensure that they adhere to these contracts:
160///
161/// * `max_size()` query and calculations in general must be correct.  Callers
162///    of this trait are expected to rely on the contract defined on each
163///    method, and implementors must ensure such contracts remain true.
164pub unsafe trait Poke {
165    /// Return the maximum number of bytes that the serialized version of `Self`
166    /// will occupy.
167    ///
168    /// # Safety
169    ///
170    /// Implementors of `Poke` guarantee to not write more than the result of
171    /// calling `max_size()` into the buffer pointed to by `bytes` when
172    /// `poke_into()` is called.
173    fn max_size() -> usize;
174    /// Serialize into the buffer pointed to by `bytes`.
175    ///
176    /// Returns a pointer to the next byte after the serialized representation of `Self`.
177    ///
178    /// # Safety
179    ///
180    /// This function is unsafe because undefined behavior can result if the
181    /// caller does not ensure all of the following:
182    ///
183    /// * `bytes` must denote a valid pointer to a block of memory.
184    ///
185    /// * `bytes` must pointer to at least the number of bytes returned by
186    ///   `max_size()`.
187    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8;
188}
189
190/// A trait for values that provide deserialization from buffers of bytes.
191///
192/// # Example
193///
194/// ```ignore
195/// use peek_poke::Peek;
196///
197/// struct Bar {
198///     a: u32,
199///     b: u8,
200///     c: i16,
201/// }
202///
203/// ...
204///
205/// impl Peek for Bar {
206///     unsafe fn peek_from(&mut self, bytes: *const u8) -> *const u8 {
207///         let bytes = self.a.peek_from(bytes);
208///         let bytes = self.b.peek_from(bytes);
209///         self.c.peek_from(bytes)
210///     }
211/// }
212/// ```
213///
214/// # Safety
215///
216/// The `Peek` trait contains unsafe methods for the following reasons, and
217/// implementors must ensure that they adhere to these contracts:
218///
219/// * Callers of this trait are expected to rely on the contract defined on each
220///   method, and implementors must ensure that `peek_from()` doesn't read more
221///   bytes from `bytes` than is returned by `Peek::max_size()`.
222pub trait Peek: Poke {
223    /// Deserialize from the buffer pointed to by `bytes`.
224    ///
225    /// Returns a pointer to the next byte after the unconsumed bytes not used
226    /// to deserialize the representation of `Self`.
227    ///
228    /// # Safety
229    ///
230    /// This function is unsafe because undefined behavior can result if the
231    /// caller does not ensure all of the following:
232    ///
233    /// * `bytes` must denote a valid pointer to a block of memory.
234    ///
235    /// * `bytes` must pointer to at least the number of bytes returned by
236    ///   `Poke::max_size()`.
237    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8;
238}
239
240macro_rules! impl_poke_for_deref {
241    (<$($desc:tt)+) => {
242        unsafe impl <$($desc)+ {
243            #[inline(always)]
244            fn max_size() -> usize {
245                <T>::max_size()
246            }
247            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
248                (**self).poke_into(bytes)
249            }
250        }
251    }
252}
253
254impl_poke_for_deref!(<'a, T: Poke> Poke for &'a T);
255impl_poke_for_deref!(<'a, T: Poke> Poke for &'a mut T);
256
257macro_rules! impl_for_primitive {
258    ($($ty:ty)+) => {
259        $(unsafe impl Poke for $ty {
260            #[inline(always)]
261            fn max_size() -> usize {
262                size_of::<Self>()
263            }
264            #[inline(always)]
265            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
266                write_verbatim(*self, bytes)
267            }
268        }
269        impl Peek for $ty {
270            #[inline(always)]
271            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
272                read_verbatim(bytes, output)
273            }
274        })+
275    };
276}
277
278impl_for_primitive! {
279    i8 i16 i32 i64 isize
280    u8 u16 u32 u64 usize
281    f32 f64
282}
283
284unsafe impl Poke for bool {
285    #[inline(always)]
286    fn max_size() -> usize {
287        u8::max_size()
288    }
289    #[inline]
290    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
291        (*self as u8).poke_into(bytes)
292    }
293}
294
295impl Peek for bool {
296    #[inline]
297    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
298        let mut int_bool = 0u8;
299        let ptr = <u8>::peek_from(bytes, &mut int_bool);
300        *output = int_bool != 0;
301        ptr
302    }
303}
304
305unsafe impl<T> Poke for PhantomData<T> {
306    #[inline(always)]
307    fn max_size() -> usize {
308        0
309    }
310    #[inline(always)]
311    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
312        bytes
313    }
314}
315
316impl<T> Peek for PhantomData<T> {
317    #[inline(always)]
318    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
319        *output = PhantomData;
320        bytes
321    }
322}
323
324unsafe impl<T: Poke> Poke for Option<T> {
325    #[inline(always)]
326    fn max_size() -> usize {
327        u8::max_size() + T::max_size()
328    }
329
330    #[inline]
331    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
332        match self {
333            None => 0u8.poke_into(bytes),
334            Some(ref v) => {
335                let bytes = 1u8.poke_into(bytes);
336                let bytes = v.poke_into(bytes);
337                bytes
338            }
339        }
340    }
341}
342
343impl<T: Default + Peek> Peek for Option<T> {
344    #[inline]
345    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
346        let (variant, bytes) = peek_from_default::<u8>(bytes);
347        match variant {
348            0 => {
349                *output = None;
350                bytes
351            }
352            1 => {
353                let (val, bytes) = peek_from_default(bytes);
354                *output = Some(val);
355                bytes
356            }
357            _ => unreachable!(),
358        }
359    }
360}
361
362macro_rules! impl_for_arrays {
363    ($($len:tt)+) => {
364        $(unsafe impl<T: Poke> Poke for [T; $len] {
365            fn max_size() -> usize {
366                $len * T::max_size()
367            }
368            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
369                self.iter().fold(bytes, |bytes, e| e.poke_into(bytes))
370            }
371        }
372        impl<T: Peek> Peek for [T; $len] {
373            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
374                (&mut *output).iter_mut().fold(bytes, |bytes, e| <T>::peek_from(bytes, e))
375            }
376        })+
377    }
378}
379
380impl_for_arrays! {
381    01 02 03 04 05 06 07 08 09 10
382    11 12 13 14 15 16 17 18 19 20
383    21 22 23 24 25 26 27 28 29 30
384    31 32
385}
386
387unsafe impl Poke for () {
388    fn max_size() -> usize {
389        0
390    }
391    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
392        bytes
393    }
394}
395impl Peek for () {
396    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
397        *output = ();
398        bytes
399    }
400}
401
402macro_rules! impl_for_tuple {
403    ($($n:tt: $ty:ident),+) => {
404        unsafe impl<$($ty: Poke),+> Poke for ($($ty,)+) {
405            #[inline(always)]
406            fn max_size() -> usize {
407                0 $(+ <$ty>::max_size())+
408            }
409            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
410                $(let bytes = self.$n.poke_into(bytes);)+
411                bytes
412            }
413        }
414        impl<$($ty: Peek),+> Peek for ($($ty,)+) {
415            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
416                $(let bytes = $ty::peek_from(bytes, &mut (*output).$n);)+
417                bytes
418            }
419        }
420    }
421}
422
423impl_for_tuple!(0: A);
424impl_for_tuple!(0: A, 1: B);
425impl_for_tuple!(0: A, 1: B, 2: C);
426impl_for_tuple!(0: A, 1: B, 2: C, 3: D);
427impl_for_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);