// Copyright 2019 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
//! Fast binary serialization and deserialization for types with a known maximum size. //! //! ## Binary Encoding Scheme //! //! ## Usage //! //! ## Comparison to bincode
use core::{marker::PhantomData, mem::size_of, slice}; usecrate::{slice_ext::*, vec_ext::*};
mod slice_ext; mod vec_ext;
union MaybeUninitShim<T: Copy> {
uninit: (),
init: T,
}
/// Peek helper for constructing a `T` by `Copy`ing into an uninitialized stack /// allocation. /// /// # Safety /// /// * `bytes` must denote a valid pointer to a block of memory. /// /// * `bytes` must point to at least the number of bytes returned by /// `Poke::max_size()`. pubunsafefn peek_from_uninit<T: Copy + Peek>(bytes: *const u8) -> (T, *const u8) { letmut val = MaybeUninitShim { uninit: () }; let bytes = <T>::peek_from(bytes, &mut val.init);
(val.init, bytes)
}
/// Peek helper for constructing a `T` by `Default` initialized stack /// allocation. /// /// # Safety /// /// * `bytes` must denote a valid pointer to a block of memory. /// /// * `bytes` must point to at least the number of bytes returned by /// `Poke::max_size()`. pubunsafefn peek_from_default<T: Default + Peek>(bytes: *const u8) -> (T, *const u8) { letmut val = T::default(); let bytes = <T>::peek_from(bytes, &mut val);
(val, bytes)
}
/// Peek inplace a `T` from a slice of bytes, returning a slice of the remaining /// bytes. `src` must contain at least `T::max_size()` bytes. /// /// [`ensure_red_zone`] can be used to add required padding. pubfn peek_from_slice<'a, T: Peek>(src: &'a [u8], dst: &mut T) -> &pan style='color:blue'>'a [u8] { unsafe { // If src.len() == T::max_size() then src is at the start of the red-zone.
assert!(T::max_size() < src.len(), "WRDL: unexpected end of display list"); let end_ptr = T::peek_from(src.as_ptr(), dst); let len = end_ptr as usize - src.as_ptr() as usize; // Did someone break the T::peek_from() can't read more than T::max_size() // bytes contract?
assert!(len <= src.len(), "WRDL: Peek::max_size was wrong");
slice::from_raw_parts(end_ptr, src.len() - len)
}
}
/// Poke helper to insert a serialized version of `src` at the beginning for `dst`. pubfn poke_inplace_slice<T: Poke>(src: &T, dst: &mut [u8]) {
assert!(T::max_size() <= dst.len(), "WRDL: buffer too small to write into"); unsafe {
src.poke_into(dst.as_mut_ptr());
}
}
/// Poke helper to append a serialized version of `src` to the end of `dst`. pubfn poke_into_vec<T: Poke>(src: &T, dst: &mut Vec<u8>) {
dst.reserve(T::max_size()); unsafe { let ptr = dst.as_end_mut_ptr(); let end_ptr = src.poke_into(ptr);
dst.set_end_ptr(end_ptr);
}
}
// TODO: Is returning the len of the iterator of any practical use? pubfn poke_extend_vec<I>(src: I, dst: &mut Vec<u8>) -> usize where
I: ExactSizeIterator,
I::Item: Poke,
{ let len = src.len(); let max_size = len * I::Item::max_size();
dst.reserve(max_size); unsafe { let ptr = dst.as_end_mut_ptr(); // Guard against the possibility of a misbehaved implementation of // ExactSizeIterator by writing at most `len` items. let end_ptr = src.take(len).fold(ptr, |ptr, item| item.poke_into(ptr));
dst.set_end_ptr(end_ptr);
}
len
}
/// Add `T::max_size()` "red zone" (padding of zeroes) to the end of the vec of /// `bytes`. This allows deserialization to assert that at least `T::max_size()` /// bytes exist at all times. pubfn ensure_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
bytes.reserve(T::max_size()); unsafe { let end_ptr = bytes.as_end_mut_ptr();
end_ptr.write_bytes(0, T::max_size());
bytes.set_end_ptr(end_ptr.add(T::max_size()));
}
}
/// Remove the "red zone" (padding of zeroes) from the end of the vec of `bytes`. /// This is effectively the inverse of `ensure_red_zone`, with the caveat that /// space reserved for the red zone is not un-reserved. Callers are repsonsible /// for making sure the vec actually has a red zone, otherwise data bytes can /// get stripped instead. pubfn strip_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
assert!(bytes.len() >= T::max_size()); unsafe { let end_ptr = bytes.as_end_mut_ptr();
bytes.set_end_ptr(end_ptr.sub(T::max_size()));
}
}
/// A trait for values that provide serialization into buffers of bytes. /// /// # Example /// /// ```no_run /// use peek_poke::Poke; /// /// struct Bar { /// a: u32, /// b: u8, /// c: i16, /// } /// /// unsafe impl Poke for Bar { /// fn max_size() -> usize { /// <u32>::max_size() + <u8>::max_size() + <i16>::max_size() /// } /// unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { /// let bytes = self.a.poke_into(bytes); /// let bytes = self.b.poke_into(bytes); /// self.c.poke_into(bytes) /// } /// } /// ``` /// /// # Safety /// /// The `Poke` trait is an `unsafe` trait for the reasons, and implementors must /// ensure that they adhere to these contracts: /// /// * `max_size()` query and calculations in general must be correct. Callers /// of this trait are expected to rely on the contract defined on each /// method, and implementors must ensure such contracts remain true. pubunsafetrait Poke { /// Return the maximum number of bytes that the serialized version of `Self` /// will occupy. /// /// # Safety /// /// Implementors of `Poke` guarantee to not write more than the result of /// calling `max_size()` into the buffer pointed to by `bytes` when /// `poke_into()` is called. fn max_size() -> usize; /// Serialize into the buffer pointed to by `bytes`. /// /// Returns a pointer to the next byte after the serialized representation of `Self`. /// /// # Safety /// /// This function is unsafe because undefined behavior can result if the /// caller does not ensure all of the following: /// /// * `bytes` must denote a valid pointer to a block of memory. /// /// * `bytes` must pointer to at least the number of bytes returned by /// `max_size()`. unsafefn poke_into(&self, bytes: *mut u8) -> *mut u8;
}
/// A trait for values that provide deserialization from buffers of bytes. /// /// # Example /// /// ```ignore /// use peek_poke::Peek; /// /// struct Bar { /// a: u32, /// b: u8, /// c: i16, /// } /// /// ... /// /// impl Peek for Bar { /// unsafe fn peek_from(&mut self, bytes: *const u8) -> *const u8 { /// let bytes = self.a.peek_from(bytes); /// let bytes = self.b.peek_from(bytes); /// self.c.peek_from(bytes) /// } /// } /// ``` /// /// # Safety /// /// The `Peek` trait contains unsafe methods for the following reasons, and /// implementors must ensure that they adhere to these contracts: /// /// * Callers of this trait are expected to rely on the contract defined on each /// method, and implementors must ensure that `peek_from()` doesn't read more /// bytes from `bytes` than is returned by `Peek::max_size()`. pubtrait Peek: Poke { /// Deserialize from the buffer pointed to by `bytes`. /// /// Returns a pointer to the next byte after the unconsumed bytes not used /// to deserialize the representation of `Self`. /// /// # Safety /// /// This function is unsafe because undefined behavior can result if the /// caller does not ensure all of the following: /// /// * `bytes` must denote a valid pointer to a block of memory. /// /// * `bytes` must pointer to at least the number of bytes returned by /// `Poke::max_size()`. unsafefn peek_from(bytes: *const u8, output: *mutSelf) -> *const u8;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.