diff options
author | Zach Reizner <zachr@google.com> | 2018-01-16 17:12:07 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-25 22:38:23 -0800 |
commit | dc17ea415101af445245cff9e5e35767f38ce2c9 (patch) | |
tree | 4cb07e8f135cbb558ed192208e30618c6df5c395 /data_model/src/lib.rs | |
parent | ea7fa562dbca413f339cf4a759152aa27b7bb3e0 (diff) | |
download | crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar.gz crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar.bz2 crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar.lz crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar.xz crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.tar.zst crosvm-dc17ea415101af445245cff9e5e35767f38ce2c9.zip |
data_model: add basic methods functions for using DataInit types
These functions are very useful C-style type casting of byte buffers to structs in a safe manner for types that implement DataInit. BUG=None TEST=None Change-Id: I4c8e1b9f7f13da5a39b65f224b65f09f31d56f1c Reviewed-on: https://chromium-review.googlesource.com/869354 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'data_model/src/lib.rs')
-rw-r--r-- | data_model/src/lib.rs | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index eeb8a5e..6f0e1c2 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use std::mem::size_of; +use std::slice::{from_raw_parts, from_raw_parts_mut}; + /// Types for which it is safe to initialize from raw data. /// /// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a @@ -9,7 +12,74 @@ /// any type that includes a reference. /// /// Implementing this trait guarantees that it is safe to instantiate the struct with random data. -pub unsafe trait DataInit: Copy + Send + Sync {} +pub unsafe trait DataInit: Copy + Send + Sync { + /// Converts a slice of raw data into a reference of `Self`. + /// + /// The value of `data` is not copied. Instead a reference is made from the given slice. The + /// value of `Self` will depend on the representation of the type in memory, and may change in + /// an unstable fashion. + /// + /// This will return `None` if the length of data does not match the size of `Self`. + fn from_slice(data: &[u8]) -> Option<&Self> { + if data.len() == size_of::<Self>() { + // Safe because the DataInit trait asserts any data is valid for this type, and we + // ensured the size of the pointer's buffer is the correct size. This aliases a pointer, + // but because the pointer is from a const slice reference, there are no mutable + // aliases. Finally, the reference returned can not outlive data because they have equal + // implicit lifetime constraints. + Some(unsafe { &*(data.as_ptr() as *const Self) }) + } else { + None + } + } + + /// Converts a mutable slice of raw data into a mutable reference of `Self`. + /// + /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned + /// reference are immediately reflected in `data`. The value of the returned `Self` will depend + /// on the representation of the type in memory, and may change in an unstable fashion. + /// + /// This will return `None` if the length of data does not match the size of `Self`. + fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> { + if data.len() == size_of::<Self>() { + // Safe because the DataInit trait asserts any data is valid for this type, and we + // ensured the size of the pointer's buffer is the correct size. This aliases a pointer, + // but because the pointer is from a const slice reference, there are no mutable + // aliases. Finally, the reference returned can not outlive data because they have equal + // implicit lifetime constraints. + Some(unsafe { &mut *(data.as_mut_ptr() as *mut Self) }) + } else { + None + } + } + + /// Converts a reference to `self` into a slice of bytes. + /// + /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`. + /// The value of bytes in the returned slice will depend on the representation of the type in + /// memory, and may change in an unstable fashion. + fn as_slice(&self) -> &[u8] { + // Safe because the entire size of self is accessible as bytes because the trait guarantees + // it. The lifetime of the returned slice is the same as the passed reference, so that no + // dangling pointers will result from this pointer alias. + unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) } + } + + /// Converts a mutable reference to `self` into a mutable slice of bytes. + /// + /// Because the slice is made from a reference to `self`, mutations to the returned slice are + /// immediately reflected in `self`. The value of bytes in the returned slice will depend on + /// the representation of the type in memory, and may change in an unstable fashion. + fn as_mut_slice(&mut self) -> &mut [u8] { + // Safe because the entire size of self is accessible as bytes because the trait guarantees + // it. The trait also guarantees that any combination of bytes is valid for this type, so + // modifying them in the form of a byte slice is valid. The lifetime of the returned slice + // is the same as the passed reference, so that no dangling pointers will result from this + // pointer alias. Although this does alias a mutable pointer, we do so by exclusively + // borrowing the given mutable reference. + unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) } + } +} // All intrinsic types and arays of intrinsic types are DataInit. They are just numbers. macro_rules! array_data_init { |