azul_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/// Remove the "red zone" (padding of zeroes) from the end of the vec of `bytes`.
117/// This is effectively the inverse of `ensure_red_zone`, with the caveat that
118/// space reserved for the red zone is not un-reserved. Callers are repsonsible
119/// for making sure the vec actually has a red zone, otherwise data bytes can
120/// get stripped instead.
121pub fn strip_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
122    assert!(bytes.len() >= 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.sub(T::max_size()));
127    }
128}
129
130#[inline]
131unsafe fn read_verbatim<T>(src: *const u8, dst: *mut T) -> *const u8 {
132    *dst = (src as *const T).read_unaligned();
133    src.add(size_of::<T>())
134}
135
136#[inline]
137unsafe fn write_verbatim<T>(src: T, dst: *mut u8) -> *mut u8 {
138    (dst as *mut T).write_unaligned(src);
139    dst.add(size_of::<T>())
140}
141
142#[cfg(feature = "extras")]
143mod euclid;
144
145/// A trait for values that provide serialization into buffers of bytes.
146///
147/// # Example
148///
149/// ```no_run
150/// use peek_poke::Poke;
151///
152/// struct Bar {
153///     a: u32,
154///     b: u8,
155///     c: i16,
156/// }
157///
158/// unsafe impl Poke for Bar {
159///     fn max_size() -> usize {
160///         <u32>::max_size() + <u8>::max_size() + <i16>::max_size()
161///     }
162///     unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
163///         let bytes = self.a.poke_into(bytes);
164///         let bytes = self.b.poke_into(bytes);
165///         self.c.poke_into(bytes)
166///     }
167/// }
168/// ```
169///
170/// # Safety
171///
172/// The `Poke` trait is an `unsafe` trait for the reasons, and implementors must
173/// ensure that they adhere to these contracts:
174///
175/// * `max_size()` query and calculations in general must be correct.  Callers
176///    of this trait are expected to rely on the contract defined on each
177///    method, and implementors must ensure such contracts remain true.
178pub unsafe trait Poke {
179    /// Return the maximum number of bytes that the serialized version of `Self`
180    /// will occupy.
181    ///
182    /// # Safety
183    ///
184    /// Implementors of `Poke` guarantee to not write more than the result of
185    /// calling `max_size()` into the buffer pointed to by `bytes` when
186    /// `poke_into()` is called.
187    fn max_size() -> usize;
188    /// Serialize into the buffer pointed to by `bytes`.
189    ///
190    /// Returns a pointer to the next byte after the serialized representation of `Self`.
191    ///
192    /// # Safety
193    ///
194    /// This function is unsafe because undefined behavior can result if the
195    /// caller does not ensure all of the following:
196    ///
197    /// * `bytes` must denote a valid pointer to a block of memory.
198    ///
199    /// * `bytes` must pointer to at least the number of bytes returned by
200    ///   `max_size()`.
201    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8;
202}
203
204/// A trait for values that provide deserialization from buffers of bytes.
205///
206/// # Example
207///
208/// ```ignore
209/// use peek_poke::Peek;
210///
211/// struct Bar {
212///     a: u32,
213///     b: u8,
214///     c: i16,
215/// }
216///
217/// ...
218///
219/// impl Peek for Bar {
220///     unsafe fn peek_from(&mut self, bytes: *const u8) -> *const u8 {
221///         let bytes = self.a.peek_from(bytes);
222///         let bytes = self.b.peek_from(bytes);
223///         self.c.peek_from(bytes)
224///     }
225/// }
226/// ```
227///
228/// # Safety
229///
230/// The `Peek` trait contains unsafe methods for the following reasons, and
231/// implementors must ensure that they adhere to these contracts:
232///
233/// * Callers of this trait are expected to rely on the contract defined on each
234///   method, and implementors must ensure that `peek_from()` doesn't read more
235///   bytes from `bytes` than is returned by `Peek::max_size()`.
236pub trait Peek: Poke {
237    /// Deserialize from the buffer pointed to by `bytes`.
238    ///
239    /// Returns a pointer to the next byte after the unconsumed bytes not used
240    /// to deserialize the representation of `Self`.
241    ///
242    /// # Safety
243    ///
244    /// This function is unsafe because undefined behavior can result if the
245    /// caller does not ensure all of the following:
246    ///
247    /// * `bytes` must denote a valid pointer to a block of memory.
248    ///
249    /// * `bytes` must pointer to at least the number of bytes returned by
250    ///   `Poke::max_size()`.
251    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8;
252}
253
254macro_rules! impl_poke_for_deref {
255    (<$($desc:tt)+) => {
256        unsafe impl <$($desc)+ {
257            #[inline(always)]
258            fn max_size() -> usize {
259                <T>::max_size()
260            }
261            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
262                (**self).poke_into(bytes)
263            }
264        }
265    }
266}
267
268impl_poke_for_deref!(<'a, T: Poke> Poke for &'a T);
269impl_poke_for_deref!(<'a, T: Poke> Poke for &'a mut T);
270
271macro_rules! impl_for_primitive {
272    ($($ty:ty)+) => {
273        $(unsafe impl Poke for $ty {
274            #[inline(always)]
275            fn max_size() -> usize {
276                size_of::<Self>()
277            }
278            #[inline(always)]
279            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
280                write_verbatim(*self, bytes)
281            }
282        }
283        impl Peek for $ty {
284            #[inline(always)]
285            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
286                read_verbatim(bytes, output)
287            }
288        })+
289    };
290}
291
292impl_for_primitive! {
293    i8 i16 i32 i64 isize
294    u8 u16 u32 u64 usize
295    f32 f64
296}
297
298unsafe impl Poke for bool {
299    #[inline(always)]
300    fn max_size() -> usize {
301        u8::max_size()
302    }
303    #[inline]
304    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
305        (*self as u8).poke_into(bytes)
306    }
307}
308
309impl Peek for bool {
310    #[inline]
311    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
312        let mut int_bool = 0u8;
313        let ptr = <u8>::peek_from(bytes, &mut int_bool);
314        *output = int_bool != 0;
315        ptr
316    }
317}
318
319unsafe impl<T> Poke for PhantomData<T> {
320    #[inline(always)]
321    fn max_size() -> usize {
322        0
323    }
324    #[inline(always)]
325    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
326        bytes
327    }
328}
329
330impl<T> Peek for PhantomData<T> {
331    #[inline(always)]
332    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
333        *output = PhantomData;
334        bytes
335    }
336}
337
338unsafe impl<T: Poke> Poke for Option<T> {
339    #[inline(always)]
340    fn max_size() -> usize {
341        u8::max_size() + T::max_size()
342    }
343
344    #[inline]
345    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
346        match self {
347            None => 0u8.poke_into(bytes),
348            Some(ref v) => {
349                let bytes = 1u8.poke_into(bytes);
350                let bytes = v.poke_into(bytes);
351                bytes
352            }
353        }
354    }
355}
356
357impl<T: Default + Peek> Peek for Option<T> {
358    #[inline]
359    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
360        let (variant, bytes) = peek_from_default::<u8>(bytes);
361        match variant {
362            0 => {
363                *output = None;
364                bytes
365            }
366            1 => {
367                let (val, bytes) = peek_from_default(bytes);
368                *output = Some(val);
369                bytes
370            }
371            _ => unreachable!(),
372        }
373    }
374}
375
376macro_rules! impl_for_arrays {
377    ($($len:tt)+) => {
378        $(unsafe impl<T: Poke> Poke for [T; $len] {
379            fn max_size() -> usize {
380                $len * T::max_size()
381            }
382            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
383                self.iter().fold(bytes, |bytes, e| e.poke_into(bytes))
384            }
385        }
386        impl<T: Peek> Peek for [T; $len] {
387            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
388                (&mut *output).iter_mut().fold(bytes, |bytes, e| <T>::peek_from(bytes, e))
389            }
390        })+
391    }
392}
393
394impl_for_arrays! {
395    01 02 03 04 05 06 07 08 09 10
396    11 12 13 14 15 16 17 18 19 20
397    21 22 23 24 25 26 27 28 29 30
398    31 32
399}
400
401unsafe impl Poke for () {
402    fn max_size() -> usize {
403        0
404    }
405    unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
406        bytes
407    }
408}
409impl Peek for () {
410    unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
411        *output = ();
412        bytes
413    }
414}
415
416macro_rules! impl_for_tuple {
417    ($($n:tt: $ty:ident),+) => {
418        unsafe impl<$($ty: Poke),+> Poke for ($($ty,)+) {
419            #[inline(always)]
420            fn max_size() -> usize {
421                0 $(+ <$ty>::max_size())+
422            }
423            unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
424                $(let bytes = self.$n.poke_into(bytes);)+
425                bytes
426            }
427        }
428        impl<$($ty: Peek),+> Peek for ($($ty,)+) {
429            unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
430                $(let bytes = $ty::peek_from(bytes, &mut (*output).$n);)+
431                bytes
432            }
433        }
434    }
435}
436
437impl_for_tuple!(0: A);
438impl_for_tuple!(0: A, 1: B);
439impl_for_tuple!(0: A, 1: B, 2: C);
440impl_for_tuple!(0: A, 1: B, 2: C, 3: D);
441impl_for_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);