1#![no_std]
41#![feature(core_intrinsics)]
42
43use core::intrinsics::transmute;
44
45pub trait Swappable {}
47
48impl Swappable for u128 {}
49impl Swappable for u64 {}
50impl Swappable for u32 {}
51impl Swappable for u16 {}
52
53impl Swappable for i128 {}
54impl Swappable for i64 {}
55impl Swappable for i32 {}
56impl Swappable for i16 {}
57
58impl Swappable for usize {}
59impl Swappable for isize {}
60
61impl Swappable for f32 {}
62impl Swappable for f64 {}
63
64#[cfg(feature = "serde")]
65use serde::{Serialize, Deserialize};
66
67#[derive(Debug, Clone, Copy, Eq, PartialEq)]
69#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
70pub struct LittleEndian<T: Swappable>(T);
71
72#[derive(Debug, Clone, Copy, Eq, PartialEq)]
74#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
75pub struct BigEndian<T: Swappable>(T);
76
77pub trait ReadAs<T: Swappable> {
78 fn read_as(&self) -> T;
79}
80
81macro_rules! into_from {
83 ($type: ident, $end: ident, $a: tt, $b: tt, $swap: tt) => {
84 impl Into<$type> for $end<$type> {
85 fn into(self) -> $type {
86 #[cfg(target_endian = $a)]
87 return self.0;
88 #[cfg(target_endian = $b)]
89 return unsafe { transmute(self.0.$swap()) };
90 }
91 }
92
93 impl From<$type> for $end<$type> {
94 fn from(value: $type) -> Self {
95 #[cfg(target_endian = $a)]
96 return Self(value);
97 #[cfg(target_endian = $b)]
98 return Self(unsafe { transmute(value.$swap()) });
99 }
100 }
101
102 impl ReadAs<$type> for $end<$type> {
103 fn read_as(&self) -> $type {
104 (*self).into()
105 }
106 }
107 };
108}
109
110macro_rules! le_into_from {
112 ($type: ident) => {
113 into_from! {$type, LittleEndian, "little", "big", to_le_bytes}
114 };
115}
116
117macro_rules! be_into_from {
119 ($type: ident) => {
120 into_from! {$type, BigEndian, "big", "little", to_be_bytes}
121 };
122}
123
124le_into_from! {u16}
125le_into_from! {u32}
126le_into_from! {u64}
127le_into_from! {u128}
128le_into_from! {usize}
129
130le_into_from! {i16}
131le_into_from! {i32}
132le_into_from! {i64}
133le_into_from! {i128}
134le_into_from! {isize}
135
136le_into_from! {f32}
137le_into_from! {f64}
138
139be_into_from! {u16}
140be_into_from! {u32}
141be_into_from! {u64}
142be_into_from! {u128}
143be_into_from! {usize}
144
145be_into_from! {i16}
146be_into_from! {i32}
147be_into_from! {i64}
148be_into_from! {i128}
149be_into_from! {isize}
150
151be_into_from! {f32}
152be_into_from! {f64}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 macro_rules! test_type {
159 ($fun: ident, $type: ident, $val: expr, $rev: expr) => {
160 #[test]
161 fn $fun() {
162 let l: LittleEndian<$type> = $val.into();
163 #[cfg(target_endian = "little")]
164 assert_eq!(l.0, $val);
165 #[cfg(target_endian = "big")]
166 assert_eq!(l.0, $rev);
167
168 let b: BigEndian<$type> = $val.into();
169 #[cfg(target_endian = "little")]
170 assert_eq!(b.0, $rev);
171 #[cfg(target_endian = "big")]
172 assert_eq!(b.0, $val);
173 }
174 };
175 }
176
177 #[test]
178 fn test_read_value() {
179 let foo: LittleEndian<u16> = 15.into();
180 foo.read_as() as u16;
181 }
182
183 test_type! {test_u128, u128, 0xaa000000000000000000000000000000, 0x000000000000000000000000000000aa}
184 test_type! {test_u64, u64, 0xaa00000000000000, 0x00000000000000aa}
185 test_type! {test_u32, u32, 0xaa000000, 0x000000aa}
186 test_type! {test_u16, u16, 0xaa00, 0x00aa}
187
188 #[cfg(target_pointer_width = "32")]
189 test_type! {test_usize, usize, 0xaa000000, 0x000000aa}
190 #[cfg(target_pointer_width = "64")]
191 test_type! {test_usize, usize, 0xaa00000000000000, 0x00000000000000aa}
192
193 #[cfg(target_pointer_width = "32")]
194 test_type! {test_isize, isize, -2isize, -16777217isize}
195 #[cfg(target_pointer_width = "64")]
196 test_type! {test_isize, isize, -2isize, -72057594037927937isize}
197
198 test_type! {test_i16, i16, -2i16, -257i16}
199 test_type! {test_i32, i32, -2i32, -16777217i32}
200 test_type! {test_i64, i64, -2i64, -72057594037927937i64}
201 test_type! {test_i128, i128, -2i128, -1329227995784915872903807060280344577i128}
202 test_type! {test_f32, f32, 1.3_f32, 272302750000000000000000_f32}
203 test_type! {test_f64, f64, 1.3_f64, -6065988000116450000000000000000000000000000000000000000000000000000_f64}
204}