Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/common/data_model/src/endian.rs
5394 views
1
// Copyright 2017 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Explicit endian types useful for embedding in structs or reinterpreting data.
6
//!
7
//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
8
//! of the equal size.
9
//!
10
//! # Examples
11
//!
12
//! ```
13
//! # use data_model::*;
14
//! let b: Be32 = From::from(3);
15
//! let l: Le32 = From::from(3);
16
//!
17
//! assert_eq!(b.to_native(), 3);
18
//! assert_eq!(l.to_native(), 3);
19
//! assert!(b == 3);
20
//! assert!(l == 3);
21
//!
22
//! // SAFETY: trivially safe
23
//! let b_trans: u32 = unsafe { std::mem::transmute(b) };
24
//! // SAFETY: trivially safe
25
//! let l_trans: u32 = unsafe { std::mem::transmute(l) };
26
//!
27
//! #[cfg(target_endian = "little")]
28
//! assert_eq!(l_trans, 3);
29
//! #[cfg(target_endian = "big")]
30
//! assert_eq!(b_trans, 3);
31
//!
32
//! assert_ne!(b_trans, l_trans);
33
//! ```
34
35
use serde::Deserialize;
36
use serde::Deserializer;
37
use serde::Serialize;
38
use serde::Serializer;
39
use zerocopy::FromBytes;
40
use zerocopy::Immutable;
41
use zerocopy::IntoBytes;
42
use zerocopy::KnownLayout;
43
44
macro_rules! endian_type {
45
($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
46
/// An integer type of with an explicit endianness.
47
///
48
/// See module level documentation for examples.
49
#[repr(transparent)]
50
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
51
pub struct $new_type($old_type);
52
53
impl $new_type {
54
/// Converts `self` to the native endianness.
55
#[inline]
56
pub fn to_native(self) -> $old_type {
57
$old_type::$from_new(self.0)
58
}
59
}
60
61
impl PartialEq<$old_type> for $new_type {
62
#[inline]
63
fn eq(&self, other: &$old_type) -> bool {
64
self.0 == $old_type::$to_new(*other)
65
}
66
}
67
68
impl PartialEq<$new_type> for $old_type {
69
#[inline]
70
fn eq(&self, other: &$new_type) -> bool {
71
$old_type::$to_new(other.0) == *self
72
}
73
}
74
75
impl From<$new_type> for $old_type {
76
#[inline]
77
fn from(v: $new_type) -> $old_type {
78
$old_type::$from_new(v.0)
79
}
80
}
81
82
impl From<$old_type> for $new_type {
83
#[inline]
84
fn from(v: $old_type) -> $new_type {
85
$new_type($old_type::$to_new(v))
86
}
87
}
88
89
impl Serialize for $new_type {
90
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91
where
92
S: Serializer,
93
{
94
self.to_native().serialize(serializer)
95
}
96
}
97
98
impl<'de> Deserialize<'de> for $new_type {
99
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100
where
101
D: Deserializer<'de>,
102
{
103
Ok($old_type::deserialize(deserializer)?.into())
104
}
105
}
106
};
107
}
108
109
endian_type!(u16, Le16, to_le, from_le);
110
endian_type!(i16, SLe16, to_le, from_le);
111
endian_type!(u32, Le32, to_le, from_le);
112
endian_type!(i32, SLe32, to_le, from_le);
113
endian_type!(u64, Le64, to_le, from_le);
114
endian_type!(i64, SLe64, to_le, from_le);
115
endian_type!(usize, LeSize, to_le, from_le);
116
endian_type!(isize, SLeSize, to_le, from_le);
117
endian_type!(u16, Be16, to_be, from_be);
118
endian_type!(i16, SBe16, to_be, from_be);
119
endian_type!(u32, Be32, to_be, from_be);
120
endian_type!(i32, SBe32, to_be, from_be);
121
endian_type!(u64, Be64, to_be, from_be);
122
endian_type!(i64, SBe64, to_be, from_be);
123
endian_type!(usize, BeSize, to_be, from_be);
124
endian_type!(isize, SBeSize, to_be, from_be);
125
126
#[cfg(test)]
127
mod tests {
128
use std::convert::From;
129
use std::mem::align_of;
130
use std::mem::size_of;
131
use std::mem::transmute;
132
133
use super::*;
134
135
#[cfg(target_endian = "little")]
136
const NATIVE_LITTLE: bool = true;
137
#[cfg(target_endian = "big")]
138
const NATIVE_LITTLE: bool = false;
139
const NATIVE_BIG: bool = !NATIVE_LITTLE;
140
141
macro_rules! endian_test {
142
($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
143
mod $test_name {
144
use super::*;
145
146
#[allow(overflowing_literals)]
147
#[test]
148
fn equality() {
149
let v = 0x0123456789ABCDEF as $old_type;
150
let endian_v: $new_type = From::from(v);
151
let endian_into: $old_type = endian_v.into();
152
// SAFETY: trivially safe
153
let endian_transmute: $old_type = unsafe { transmute(endian_v) };
154
155
if $native {
156
assert_eq!(endian_v, endian_transmute);
157
} else {
158
assert_eq!(endian_v, endian_transmute.swap_bytes());
159
}
160
161
assert_eq!(v, endian_into);
162
assert!(v == endian_v);
163
assert!(endian_v == v);
164
}
165
166
#[test]
167
fn alignment() {
168
assert_eq!(align_of::<$new_type>(), align_of::<$old_type>());
169
}
170
171
#[test]
172
fn size() {
173
assert_eq!(size_of::<$new_type>(), size_of::<$old_type>());
174
}
175
}
176
};
177
}
178
179
endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
180
endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
181
endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
182
endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
183
endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
184
endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
185
endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
186
endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
187
endian_test!(u16, Be16, test_be16, NATIVE_BIG);
188
endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
189
endian_test!(u32, Be32, test_be32, NATIVE_BIG);
190
endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
191
endian_test!(u64, Be64, test_be64, NATIVE_BIG);
192
endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
193
endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
194
endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
195
}
196
197