ab_riscv_primitives/instructions/
utils.rs1#[cfg(test)]
4mod tests;
5
6use core::fmt;
7use core::ops::{Shl, Shr};
8
9#[derive(Clone, Copy, Hash)]
11#[derive_const(PartialEq, Eq)]
12pub struct U24([u8; 3]);
13
14const impl Default for U24 {
15 #[inline(always)]
16 fn default() -> Self {
17 Self([0; _])
18 }
19}
20
21impl fmt::Debug for U24 {
22 #[inline(always)]
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 fmt::Debug::fmt(&self.to_u32(), f)
25 }
26}
27
28impl fmt::Display for U24 {
29 #[inline(always)]
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 fmt::Display::fmt(&self.to_u32(), f)
32 }
33}
34
35impl fmt::LowerHex for U24 {
36 #[inline(always)]
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 fmt::LowerHex::fmt(&self.to_u32(), f)
39 }
40}
41
42impl fmt::UpperHex for U24 {
43 #[inline(always)]
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 fmt::UpperHex::fmt(&self.to_u32(), f)
46 }
47}
48
49const impl Shl<u8> for U24 {
50 type Output = Self;
51
52 #[inline(always)]
53 fn shl(self, rhs: u8) -> Self::Output {
54 Self::from_u32(self.to_u32().shl(rhs))
55 }
56}
57
58const impl Shr<u8> for U24 {
59 type Output = Self;
60
61 #[inline(always)]
62 fn shr(self, rhs: u8) -> Self::Output {
63 Self::from_u32(self.to_u32().shr(rhs))
64 }
65}
66
67const impl Shl<u8> for &U24 {
68 type Output = U24;
69
70 #[inline(always)]
71 fn shl(self, rhs: u8) -> Self::Output {
72 U24::from_u32(self.to_u32().shl(rhs))
73 }
74}
75
76const impl Shr<u8> for &U24 {
77 type Output = U24;
78
79 #[inline(always)]
80 fn shr(self, rhs: u8) -> Self::Output {
81 U24::from_u32(self.to_u32().shr(rhs))
82 }
83}
84
85const impl From<U24> for u32 {
86 #[inline(always)]
87 fn from(v: U24) -> Self {
88 v.to_u32()
89 }
90}
91
92const impl From<U24> for u64 {
93 #[inline(always)]
94 fn from(v: U24) -> Self {
95 u64::from(v.to_u32())
96 }
97}
98
99impl U24 {
100 #[inline(always)]
104 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
105 pub const fn from_u32(v: u32) -> Self {
106 let b = v.to_le_bytes();
107 debug_assert!(
108 (v << u8::BITS) >> u8::BITS == v,
109 "Input value exceeds 24 bits"
110 );
111 Self([b[0], b[1], b[2]])
112 }
113
114 #[inline(always)]
116 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
117 pub const fn to_u32(self) -> u32 {
118 let [a, b, c] = self.0;
119 u32::from_le_bytes([a, b, c, 0])
120 }
121}
122
123#[derive(Clone, Copy, Hash)]
125#[derive_const(PartialEq, Eq)]
126pub struct I24([u8; 3]);
127
128const impl Default for I24 {
129 #[inline(always)]
130 fn default() -> Self {
131 Self([0; _])
132 }
133}
134
135impl fmt::Debug for I24 {
136 #[inline(always)]
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 fmt::Debug::fmt(&self.to_i32(), f)
139 }
140}
141
142impl fmt::Display for I24 {
143 #[inline(always)]
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 fmt::Display::fmt(&self.to_i32(), f)
146 }
147}
148
149impl fmt::LowerHex for I24 {
150 #[inline(always)]
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 fmt::LowerHex::fmt(&self.to_i32(), f)
153 }
154}
155
156impl fmt::UpperHex for I24 {
157 #[inline(always)]
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 fmt::UpperHex::fmt(&self.to_i32(), f)
160 }
161}
162
163const impl Shl<u8> for I24 {
164 type Output = Self;
165
166 #[inline(always)]
167 fn shl(self, rhs: u8) -> Self::Output {
168 Self::from_i32(self.to_i32().shl(rhs))
169 }
170}
171
172const impl Shr<u8> for I24 {
173 type Output = Self;
174
175 #[inline(always)]
176 fn shr(self, rhs: u8) -> Self::Output {
177 Self::from_i32(self.to_i32().shr(rhs))
178 }
179}
180
181const impl Shl<u8> for &I24 {
182 type Output = I24;
183
184 #[inline(always)]
185 fn shl(self, rhs: u8) -> Self::Output {
186 I24::from_i32(self.to_i32().shl(rhs))
187 }
188}
189
190const impl Shr<u8> for &I24 {
191 type Output = I24;
192
193 #[inline(always)]
194 fn shr(self, rhs: u8) -> Self::Output {
195 I24::from_i32(self.to_i32().shr(rhs))
196 }
197}
198
199const impl From<I24> for i32 {
200 #[inline(always)]
201 fn from(v: I24) -> Self {
202 v.to_i32()
203 }
204}
205
206const impl From<I24> for i64 {
207 #[inline(always)]
208 fn from(v: I24) -> Self {
209 i64::from(v.to_i32())
210 }
211}
212
213impl I24 {
214 #[inline(always)]
218 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
219 pub const fn from_i32(v: i32) -> Self {
220 let b = v.to_le_bytes();
221 debug_assert!(
222 (v << u8::BITS) >> u8::BITS == v,
223 "Input value exceeds 24 bits"
224 );
225 Self([b[0], b[1], b[2]])
226 }
227
228 #[inline(always)]
230 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
231 pub const fn to_i32(self) -> i32 {
232 let [a, b, c] = self.0;
233 i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS
235 }
236}
237
238#[derive(Clone, Copy, Hash)]
241#[derive_const(PartialEq, Eq)]
242pub struct I24WithZeroedBits<const LOW_ZEROED_BITS: u8>([u8; 3]);
243
244const impl<const LOW_ZEROED_BITS: u8> Default for I24WithZeroedBits<LOW_ZEROED_BITS> {
245 #[inline(always)]
246 fn default() -> Self {
247 Self([0; _])
248 }
249}
250
251impl<const LOW_ZEROED_BITS: u8> fmt::Debug for I24WithZeroedBits<LOW_ZEROED_BITS> {
252 #[inline(always)]
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 fmt::Debug::fmt(&self.to_i32(), f)
255 }
256}
257
258impl<const LOW_ZEROED_BITS: u8> fmt::Display for I24WithZeroedBits<LOW_ZEROED_BITS> {
259 #[inline(always)]
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 fmt::Display::fmt(&self.to_i32(), f)
262 }
263}
264
265impl<const LOW_ZEROED_BITS: u8> fmt::LowerHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
266 #[inline(always)]
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 fmt::LowerHex::fmt(&self.to_i32(), f)
269 }
270}
271
272impl<const LOW_ZEROED_BITS: u8> fmt::UpperHex for I24WithZeroedBits<LOW_ZEROED_BITS> {
273 #[inline(always)]
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 fmt::UpperHex::fmt(&self.to_i32(), f)
276 }
277}
278
279const impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i32 {
280 #[inline(always)]
281 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
282 v.to_i32()
283 }
284}
285
286const impl<const LOW_ZEROED_BITS: u8> From<I24WithZeroedBits<LOW_ZEROED_BITS>> for i64 {
287 #[inline(always)]
288 fn from(v: I24WithZeroedBits<LOW_ZEROED_BITS>) -> Self {
289 i64::from(v.to_i32())
290 }
291}
292
293impl<const LOW_ZEROED_BITS: u8> I24WithZeroedBits<LOW_ZEROED_BITS> {
294 #[inline(always)]
300 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
301 pub const fn from_i32(v_original: i32) -> Self {
302 let v = v_original >> LOW_ZEROED_BITS;
303 let b = v.to_le_bytes();
304 let return_value = Self([b[0], b[1], b[2]]);
305
306 debug_assert!(
307 return_value.to_i32() == v_original,
308 "Input has non-zero low bits"
309 );
310
311 return_value
312 }
313
314 #[inline(always)]
316 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
317 pub const fn to_i32(self) -> i32 {
318 let [a, b, c] = self.0;
319 (((i32::from_le_bytes([a, b, c, 0]) << u8::BITS >> u8::BITS) << LOW_ZEROED_BITS)
321 .cast_unsigned()
322 & (u32::MAX << LOW_ZEROED_BITS))
323 .cast_signed()
324 }
325}