summary refs log tree commit diff
path: root/data_model
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2017-06-22 14:04:43 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-27 06:39:56 -0700
commit8c04d70b7db3df320eda1cdda42f7d323152a3a6 (patch)
treedc2914e521a177ddc92fc3fee6abb6854b91840f /data_model
parent0584fe9fb2694fad6dc841a8215e8017c18b19c7 (diff)
downloadcrosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar.gz
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar.bz2
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar.lz
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar.xz
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.tar.zst
crosvm-8c04d70b7db3df320eda1cdda42f7d323152a3a6.zip
data_model: add unsigned endian types
These types are just like normal unsigned primitives, except their
endian is explicit.

TEST=cargo test
BUG=None

Change-Id: I3d0a7f7ccbf276e2cfdb34310f173df193c70c79
Reviewed-on: https://chromium-review.googlesource.com/544692
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Diffstat (limited to 'data_model')
-rw-r--r--data_model/src/endian.rs145
-rw-r--r--data_model/src/lib.rs3
2 files changed, 148 insertions, 0 deletions
diff --git a/data_model/src/endian.rs b/data_model/src/endian.rs
new file mode 100644
index 0000000..d1a25a9
--- /dev/null
+++ b/data_model/src/endian.rs
@@ -0,0 +1,145 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Explicit endian types useful for embedding in structs or reinterpreting data.
+//!
+//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
+//! of the equal size.
+//!
+//! # Examples
+//!
+//! ```
+//! # use  data_model::*;
+//!   let b: Be32 = From::from(3);
+//!   let l: Le32 = From::from(3);
+//!
+//!   assert_eq!(b.to_native(), 3);
+//!   assert_eq!(l.to_native(), 3);
+//!   assert!(b == 3);
+//!   assert!(l == 3);
+//!
+//!   let b_trans: u32 = unsafe { std::mem::transmute(b) };
+//!   let l_trans: u32 = unsafe { std::mem::transmute(l) };
+//!
+//!   #[cfg(target_endian = "little")]
+//!   assert_eq!(l_trans, 3);
+//!   #[cfg(target_endian = "big")]
+//!   assert_eq!(b_trans, 3);
+//!
+//!   assert_ne!(b_trans, l_trans);
+//! ```
+
+use DataInit;
+
+macro_rules! endian_type {
+    ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => (
+        /// An unsigned integer type of with an explicit endianness.
+        ///
+        /// See module level documentation for examples.
+        #[derive(Copy, Clone, Eq, PartialEq, Debug)]
+        pub struct $new_type($old_type);
+
+        impl $new_type {
+            /// Converts `self` to the native endianness.
+            pub fn to_native(self) -> $old_type {
+                $old_type::$from_new(self.0)
+            }
+        }
+
+        unsafe impl DataInit for $new_type {}
+
+        impl PartialEq<$old_type> for $new_type {
+            fn eq(&self, other: &$old_type) -> bool {
+                self.0 == $old_type::$to_new(*other)
+            }
+        }
+
+        impl PartialEq<$new_type> for $old_type {
+            fn eq(&self, other: &$new_type) -> bool {
+                $old_type::$to_new(other.0) == *self
+            }
+        }
+
+        impl Into<$old_type> for $new_type {
+            fn into(self) -> $old_type {
+                $old_type::$from_new(self.0)
+            }
+        }
+
+        impl From<$old_type> for $new_type {
+            fn from(v: $old_type) -> $new_type {
+                $new_type($old_type::$to_new(v))
+            }
+        }
+    )
+}
+
+endian_type!(u16, Le16, to_le, from_le);
+endian_type!(u32, Le32, to_le, from_le);
+endian_type!(u64, Le64, to_le, from_le);
+endian_type!(usize, LeSize, to_le, from_le);
+endian_type!(u16, Be16, to_be, from_be);
+endian_type!(u32, Be32, to_be, from_be);
+endian_type!(u64, Be64, to_be, from_be);
+endian_type!(usize, BeSize, to_be, from_be);
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::convert::From;
+    use std::mem::{size_of, align_of, transmute};
+
+    #[cfg(target_endian = "little")]
+    const NATIVE_LITTLE: bool = true;
+    #[cfg(target_endian = "big")]
+    const NATIVE_LITTLE: bool = false;
+    const NATIVE_BIG: bool = !NATIVE_LITTLE;
+
+    macro_rules! endian_test {
+        ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => (
+            mod $test_name {
+                use super::*;
+
+                #[test]
+                fn align() {
+                    assert_eq!(align_of::<$new_type>(), align_of::<$old_type>());
+                }
+
+                #[test]
+                fn size() {
+                    assert_eq!(size_of::<$new_type>(), size_of::<$old_type>());
+                }
+
+                #[allow(overflowing_literals)]
+                #[test]
+                fn equality() {
+                    let v = 0x0123456789ABCDEF as $old_type;
+                    let endian_v: $new_type = From::from(v);
+                    let endian_into: $old_type = endian_v.into();
+                    let endian_transmute: $old_type = unsafe { transmute(endian_v) };
+
+                    if $native {
+                        assert_eq!(endian_v, endian_transmute);
+                    } else {
+                        assert_eq!(endian_v, endian_transmute.swap_bytes());
+                    }
+
+                    assert_eq!(v, endian_into);
+                    assert!(v == endian_v);
+                    assert!(endian_v == v);
+                }
+            }
+        )
+    }
+
+    endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
+    endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
+    endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
+    endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
+    endian_test!(u16, Be16, test_be16, NATIVE_BIG);
+    endian_test!(u32, Be32, test_be32, NATIVE_BIG);
+    endian_test!(u64, Be64, test_be64, NATIVE_BIG);
+    endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
+}
diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs
index 895f9ad..389ca9f 100644
--- a/data_model/src/lib.rs
+++ b/data_model/src/lib.rs
@@ -41,3 +41,6 @@ data_init_type!(i16);
 data_init_type!(i32);
 data_init_type!(i64);
 data_init_type!(isize);
+
+pub mod endian;
+pub use endian::*;