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