perf_event_data/
endian.rs

1//! Traits and types for converting between a source endianness and that of the
2//! current host.
3//!
4//! Usually you will want [`Native`] endian if parsing data emitted by the
5//! kernel otherwise you will likely want [`Dynamic`] endian if parsing data
6//! from a file, although [`Little`] or [`Big`] endian may also work.
7
8/// A trait containing the required conversion functions needed to parse perf
9/// records.
10///
11/// # Safety
12/// If [`is_native`](Endian::is_native) returns true when the source endianness
13/// does not match the current host endianness then UB will occur.
14pub unsafe trait Endian: Clone {
15    /// Convert a `u16` from the source endian to the native endian.
16    fn convert_u16(&self, bytes: [u8; 2]) -> u16;
17
18    /// Convert a `u32` from the source endian to the native endian.
19    fn convert_u32(&self, bytes: [u8; 4]) -> u32;
20
21    /// Convert a `u64` from the source endian to the native endian.
22    fn convert_u64(&self, bytes: [u8; 8]) -> u64;
23
24    /// Whether the source endian is the same as the current native endian.
25    ///
26    /// If this returns `true` then the parser will attempt to avoid copying
27    /// some data out of the source buffer, instead reinterpreting it when
28    /// possible.
29    fn is_native(&self) -> bool {
30        false
31    }
32}
33
34/// Native endian.
35///
36/// This type performs no endianness conversion.
37#[derive(Copy, Clone, Debug, Default)]
38pub struct Native;
39
40unsafe impl Endian for Native {
41    #[inline]
42    fn convert_u16(&self, bytes: [u8; 2]) -> u16 {
43        u16::from_ne_bytes(bytes)
44    }
45
46    #[inline]
47    fn convert_u32(&self, bytes: [u8; 4]) -> u32 {
48        u32::from_ne_bytes(bytes)
49    }
50
51    #[inline]
52    fn convert_u64(&self, bytes: [u8; 8]) -> u64 {
53        u64::from_ne_bytes(bytes)
54    }
55
56    #[inline]
57    fn is_native(&self) -> bool {
58        true
59    }
60}
61
62/// Little endian.
63#[derive(Copy, Clone, Debug, Default)]
64pub struct Little;
65
66unsafe impl Endian for Little {
67    #[inline]
68    fn convert_u16(&self, bytes: [u8; 2]) -> u16 {
69        u16::from_le_bytes(bytes)
70    }
71
72    #[inline]
73    fn convert_u32(&self, bytes: [u8; 4]) -> u32 {
74        u32::from_le_bytes(bytes)
75    }
76
77    #[inline]
78    fn convert_u64(&self, bytes: [u8; 8]) -> u64 {
79        u64::from_le_bytes(bytes)
80    }
81
82    #[inline]
83    fn is_native(&self) -> bool {
84        let bytes = [b'a', b'b'];
85
86        u16::from_le_bytes(bytes) == u16::from_ne_bytes(bytes)
87    }
88}
89
90/// Big endian.
91#[derive(Copy, Clone, Debug, Default)]
92pub struct Big;
93
94unsafe impl Endian for Big {
95    #[inline]
96    fn convert_u16(&self, bytes: [u8; 2]) -> u16 {
97        u16::from_be_bytes(bytes)
98    }
99
100    #[inline]
101    fn convert_u32(&self, bytes: [u8; 4]) -> u32 {
102        u32::from_be_bytes(bytes)
103    }
104
105    #[inline]
106    fn convert_u64(&self, bytes: [u8; 8]) -> u64 {
107        u64::from_be_bytes(bytes)
108    }
109
110    #[inline]
111    fn is_native(&self) -> bool {
112        let bytes = [b'a', b'b'];
113
114        u16::from_be_bytes(bytes) == u16::from_ne_bytes(bytes)
115    }
116}
117
118/// Either big or little endian, chosen at runtime.
119#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
120pub enum Dynamic {
121    /// Big endian.
122    Big,
123
124    /// Little endian.
125    Little,
126}
127
128unsafe impl Endian for Dynamic {
129    fn convert_u16(&self, bytes: [u8; 2]) -> u16 {
130        match self {
131            Self::Big => Big.convert_u16(bytes),
132            Self::Little => Little.convert_u16(bytes),
133        }
134    }
135
136    fn convert_u32(&self, bytes: [u8; 4]) -> u32 {
137        match self {
138            Self::Big => Big.convert_u32(bytes),
139            Self::Little => Little.convert_u32(bytes),
140        }
141    }
142
143    fn convert_u64(&self, bytes: [u8; 8]) -> u64 {
144        match self {
145            Self::Big => Big.convert_u64(bytes),
146            Self::Little => Little.convert_u64(bytes),
147        }
148    }
149
150    fn is_native(&self) -> bool {
151        match self {
152            Self::Big => Big.is_native(),
153            Self::Little => Little.is_native(),
154        }
155    }
156}