1pub trait Scalar: Sized {
10 type Raw: sealed::BeByteArray;
12
13 fn from_raw(raw: Self::Raw) -> Self;
15
16 fn to_raw(self) -> Self::Raw;
18
19 fn read(slice: &[u8]) -> Option<Self> {
24 sealed::BeByteArray::from_slice(slice).map(Self::from_raw)
25 }
26}
27
28pub trait FixedSize: Sized {
30 const RAW_BYTE_LEN: usize;
42}
43
44mod sealed {
47 #[cfg(not(feature = "bytemuck"))]
52 pub trait BeByteArray: Copy + AsRef<[u8]> {
53 fn from_slice(slice: &[u8]) -> Option<Self>;
55 }
56 #[cfg(feature = "bytemuck")]
57 pub trait BeByteArray:
58 Copy + AsRef<[u8]> + bytemuck::AnyBitPattern + bytemuck::Zeroable
59 {
60 fn from_slice(slice: &[u8]) -> Option<Self>;
62 }
63
64 impl<const N: usize> BeByteArray for [u8; N] {
65 fn from_slice(slice: &[u8]) -> Option<Self> {
66 slice.try_into().ok()
67 }
68 }
69}
70
71#[derive(Clone, Copy, PartialEq, Eq, Hash)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74#[repr(transparent)]
75pub struct BigEndian<T: Scalar>(pub(crate) T::Raw);
76
77#[cfg(feature = "bytemuck")]
82unsafe impl<T> bytemuck::Zeroable for BigEndian<T> where T: Scalar + Copy {}
83#[cfg(feature = "bytemuck")]
84unsafe impl<T> bytemuck::AnyBitPattern for BigEndian<T> where T: Scalar + Copy + 'static {}
85
86impl<T: Scalar> BigEndian<T> {
87 pub fn new(raw: T::Raw) -> BigEndian<T> {
89 BigEndian(raw)
90 }
91
92 pub fn from_slice(slice: &[u8]) -> Option<Self> {
96 sealed::BeByteArray::from_slice(slice).map(Self)
97 }
98
99 #[inline(always)]
101 pub fn get(&self) -> T {
102 T::from_raw(self.0)
103 }
104
105 pub fn set(&mut self, value: T) {
107 self.0 = value.to_raw();
108 }
109
110 pub fn be_bytes(&self) -> &[u8] {
112 self.0.as_ref()
113 }
114}
115
116impl<T: Scalar> From<T> for BigEndian<T> {
117 #[inline]
118 fn from(val: T) -> Self {
119 BigEndian(val.to_raw())
120 }
121}
122
123impl<T: Scalar + Default> Default for BigEndian<T> {
124 fn default() -> Self {
125 Self::from(T::default())
126 }
127}
128
129impl<T: Scalar + Copy + PartialEq> PartialEq<T> for BigEndian<T> {
132 fn eq(&self, other: &T) -> bool {
133 self.get() == *other
134 }
135}
136
137impl<T: Scalar + Copy + PartialOrd + PartialEq> PartialOrd for BigEndian<T>
138where
139 <T as Scalar>::Raw: PartialEq,
140{
141 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
142 self.get().partial_cmp(&other.get())
143 }
144}
145
146impl<T: Scalar + Copy + Ord + Eq> Ord for BigEndian<T>
147where
148 <T as Scalar>::Raw: Eq,
149{
150 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
151 self.get().cmp(&other.get())
152 }
153}
154
155impl<T: Scalar> FixedSize for T {
156 const RAW_BYTE_LEN: usize = std::mem::size_of::<T::Raw>();
157}
158
159impl<T: Scalar> FixedSize for BigEndian<T> {
160 const RAW_BYTE_LEN: usize = T::RAW_BYTE_LEN;
161}
162
163#[macro_export]
165macro_rules! newtype_scalar {
166 ($ty:ident, $raw:ty) => {
167 impl $crate::raw::Scalar for $ty {
168 type Raw = $raw;
169 fn to_raw(self) -> $raw {
170 self.0.to_raw()
171 }
172
173 #[inline(always)]
174 fn from_raw(raw: $raw) -> Self {
175 Self($crate::raw::Scalar::from_raw(raw))
176 }
177 }
178 };
179}
180
181macro_rules! int_scalar {
182 ($ty:ty, $raw:ty) => {
183 impl crate::raw::Scalar for $ty {
184 type Raw = $raw;
185 fn to_raw(self) -> $raw {
186 self.to_be_bytes()
187 }
188
189 #[inline(always)]
190 fn from_raw(raw: $raw) -> $ty {
191 Self::from_be_bytes(raw)
192 }
193 }
194 };
195}
196
197int_scalar!(u8, [u8; 1]);
198int_scalar!(i8, [u8; 1]);
199int_scalar!(u16, [u8; 2]);
200int_scalar!(i16, [u8; 2]);
201int_scalar!(u32, [u8; 4]);
202int_scalar!(i32, [u8; 4]);
203int_scalar!(i64, [u8; 8]);
204int_scalar!(crate::Uint24, [u8; 3]);
205int_scalar!(crate::Int24, [u8; 3]);
206
207impl<T: std::fmt::Debug + Scalar + Copy> std::fmt::Debug for BigEndian<T> {
208 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
209 self.get().fmt(f)
210 }
211}
212
213impl<T: std::fmt::Display + Scalar + Copy> std::fmt::Display for BigEndian<T> {
214 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
215 self.get().fmt(f)
216 }
217}