1use std::cmp::Ordering;
2use std::fmt::{self, Debug, Formatter, Octal};
3use std::hash::{Hash, Hasher};
4
5use super::error::ConversionFailed;
6use super::unsigned::{
7 Unsigned5Bit, Unsigned6Bit, Unsigned9Bit, Unsigned12Bit, Unsigned18Bit, Unsigned36Bit,
8};
9use super::{Signum, WordCommon};
10
11#[cfg(test)]
12mod tests18;
13#[cfg(test)]
14mod tests36;
15#[cfg(test)]
16mod tests5;
17#[cfg(test)]
18mod tests9;
19
20macro_rules! from_native_type_to_self {
23 ($SelfT:ty, $InnerT:ty, $SignedInnerT:ty, $($from:ty)*) => {
24 $(
25 impl From<$from> for $SelfT {
26 fn from(n: $from) -> Self {
27 let v: $SignedInnerT = n.into();
28 Self {
29 bits: <$SelfT>::convert_to_ones_complement(v),
30 }
31 }
32 }
33 )*
34 }
35}
36
37macro_rules! try_from_native_type_to_self {
38 ($SelfT:ty, $InnerT:ty, $SignedInnerT:ty, $($from:ty)*) => {
39 $(
40 impl TryFrom<$from> for $SelfT {
41 type Error = ConversionFailed;
42 fn try_from(n: $from) -> Result<$SelfT, ConversionFailed> {
43 match n.try_into() {
44 Err(_) if n > 0 => Err(ConversionFailed::TooLarge),
45 Err(_) => Err(ConversionFailed::TooSmall),
46 Ok(signed_value) => {
47 if signed_value > (Self::VALUE_BITS as $SignedInnerT) {
48 Err(ConversionFailed::TooLarge)
49 } else if signed_value < -(Self::VALUE_BITS as $SignedInnerT) {
50 Err(ConversionFailed::TooSmall)
51 } else {
52 Ok(Self {
53 bits: <$SelfT>::convert_to_ones_complement(signed_value)
54 })
55 }
56 }
57 }
58 }
59 }
60 )*
61 }
62}
63
64macro_rules! from_self_to_native_type {
67 ($SelfT:ty, $InnerT:ty, $SignedInnerT:ty, $($to:ty)*) => {
68 $(
69 impl From<$SelfT> for $to {
70 fn from(n: $SelfT) -> $to {
71 if n.is_zero() {
72 0 as Self
73 } else if n.is_negative() {
74 let inverted_bits = (!n.bits) & <$SelfT>::VALUE_BITS;
75 let absolute_value = inverted_bits as $SignedInnerT;
76 (-absolute_value) as Self
77 } else {
78 n.bits as Self
79 }
80 }
81 }
82 )*
83 }
84}
85
86macro_rules! try_from_self_to_native_type {
89 ($SelfT:ty, $InnerT:ty, $SignedInnerT:ty, $($to:ty)*) => {
90 $(
91 impl TryFrom<$SelfT> for $to {
92 type Error = ConversionFailed;
93 fn try_from(n: $SelfT) -> Result<$to, ConversionFailed> {
94 if n.is_zero() {
95 return Ok(0);
96 }
97 #[allow(unused_comparisons)]
98 if n.is_negative() {
99 let inverted_bits: $InnerT = (!n.bits) & <$SelfT>::VALUE_BITS;
100 let absolute_value: $SignedInnerT = inverted_bits as $SignedInnerT;
101 <$to>::try_from(-absolute_value)
102 .map_err(|_| ConversionFailed::TooSmall)
103 } else {
104 <$to>::try_from(n.bits)
105 .map_err(|_| ConversionFailed::TooLarge)
106 }
107 }
108 }
109 )*
110 }
111}
112
113macro_rules! signed_ones_complement_impl {
114 ($SelfT:ty, $BITS:expr_2021, $InnerT:ty, $SignedInnerT:ty, $UnsignedPeerT:ty) => {
115 impl $SelfT {
116 const SIGN_BIT: $InnerT = 1 << ($BITS - 1);
117 const VALUE_BITS: $InnerT = Self::SIGN_BIT - 1;
118 const ALL_BITS: $InnerT = Self::SIGN_BIT | Self::VALUE_BITS;
119
120 pub const MAX: Self = Self {
121 bits: Self::VALUE_BITS,
122 };
123
124 pub const MIN: Self = Self {
125 bits: Self::SIGN_BIT,
126 };
127
128 pub const ZERO: Self = Self { bits: 0 };
129 pub const MINUS_ZERO: Self = Self {
130 bits: Self::ALL_BITS,
131 };
132 pub const ONE: Self = Self { bits: 1 };
133
134 pub const fn is_positive_zero(&self) -> bool {
135 self.bits == 0
136 }
137
138 pub const fn is_negative_zero(&self) -> bool {
139 self.bits == Self::ALL_BITS
140 }
141
142 pub const fn is_zero(&self) -> bool {
143 self.is_positive_zero() || self.is_negative_zero()
144 }
145
146 pub const fn reinterpret_as_unsigned(&self) -> $UnsignedPeerT {
147 type T = $UnsignedPeerT;
148 T { bits: self.bits }
149 }
150
151 pub const fn is_negative(&self) -> bool {
152 self.bits & Self::SIGN_BIT != 0 && !self.is_zero()
153 }
154
155 pub const fn is_positive(&self) -> bool {
156 self.bits & Self::SIGN_BIT == 0 || self.is_zero()
157 }
158
159 pub const fn convert_to_ones_complement(signed: $SignedInnerT) -> $InnerT {
160 if signed < 0 {
161 let absolute: $InnerT = (-signed) as $InnerT;
162 let bits: $InnerT = (!absolute) & Self::ALL_BITS;
163 bits
164 } else {
165 signed as $InnerT
166 }
167 }
168
169 pub fn checked_add(self, rhs: $SelfT) -> Option<$SelfT> {
170 let left = <$SignedInnerT>::from(self);
171 let right = <$SignedInnerT>::from(rhs);
172 match left.checked_add(right) {
173 Some(result) => Self::try_from(result).ok(),
174 None => None,
175 }
176 }
177
178 pub fn checked_sub(self, rhs: $SelfT) -> Option<$SelfT> {
179 let left = <$SignedInnerT>::from(self);
180 let right = <$SignedInnerT>::from(rhs);
181 match left.checked_sub(right) {
182 Some(result) => Self::try_from(result).ok(),
183 None => None,
184 }
185 }
186
187 #[must_use]
188 pub fn wrapping_add(self, rhs: $SelfT) -> $SelfT {
189 const MODULUS: $SignedInnerT = 1 << ($BITS - 1);
190 let left = <$SignedInnerT>::from(self);
191 let right = <$SignedInnerT>::from(rhs);
192 let (result, overflow) = left.overflowing_add(right);
193 if overflow {
194 panic!(
195 "bug: $SignedInnerT is not wide enough to perform no-overflow arithmetic"
196 );
197 }
198 Self {
199 bits: Self::convert_to_ones_complement(result % MODULUS),
200 }
201 }
202
203 #[must_use]
204 pub fn wrapping_sub(self, rhs: $SelfT) -> $SelfT {
205 const MODULUS: $SignedInnerT = 1 << ($BITS - 1);
206 let left = <$SignedInnerT>::from(self);
207 let right = <$SignedInnerT>::from(rhs);
208 let (result, overflow) = left.overflowing_sub(right);
209 if overflow {
210 panic!(
211 "bug: $SignedInnerT is not wide enough to perform no-overflow arithmetic"
212 );
213 }
214 Self {
215 bits: Self::convert_to_ones_complement(result % MODULUS),
216 }
217 }
218
219 pub fn checked_div(self, rhs: $SelfT) -> Option<$SelfT> {
220 if rhs.is_zero() {
221 None
222 } else {
223 let left = <$SignedInnerT>::from(self);
224 let right = <$SignedInnerT>::from(rhs);
225 match left.checked_div(right) {
226 Some(result) => Self::try_from(result).ok(),
227 None => unreachable!("division cannot overflow if rhs is nonzero"),
228 }
229 }
230 }
231
232 #[must_use]
233 pub const fn abs(self) -> Self {
234 if self.is_zero() {
235 Self::ZERO
236 } else if self.is_negative() {
237 Self {
238 bits: (!self.bits) & Self::VALUE_BITS,
239 }
240 } else {
241 self
242 }
243 }
244
245 pub const fn overflowing_abs(self) -> (Self, bool) {
246 (self.abs(), false)
247 }
248 }
249
250 impl Default for $SelfT {
251 fn default() -> Self {
252 Self { bits: 0 }
253 }
254 }
255
256 impl Octal for $SelfT {
257 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
258 Octal::fmt(&self.bits, f)
259 }
260 }
261
262 impl Debug for $SelfT {
263 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
264 write!(f, concat!(stringify!($SelfT), "{{bits: {:#o}}}"), self.bits)
265 }
266 }
267
268 impl Hash for $SelfT {
269 fn hash<H>(&self, state: &mut H)
270 where
271 H: Hasher,
272 {
273 if self.is_zero() {
274 let instead: $InnerT = 0;
276 instead.hash(state)
277 } else {
278 self.bits.hash(state)
279 }
280 }
281 }
282
283 impl PartialEq for $SelfT {
284 fn eq(&self, other: &$SelfT) -> bool {
285 match self.cmp(other) {
286 Ordering::Equal => true,
287 _ => false,
288 }
289 }
290 }
291
292 impl PartialEq<$SignedInnerT> for $SelfT {
293 fn eq(&self, other: &$SignedInnerT) -> bool {
294 match self.partial_cmp(other) {
295 Some(Ordering::Equal) => true,
296 _ => false,
297 }
298 }
299 }
300
301 impl Eq for $SelfT {}
302
303 impl PartialOrd for $SelfT {
304 fn partial_cmp(&self, other: &$SelfT) -> Option<Ordering> {
305 Some(self.cmp(other))
306 }
307 }
308
309 impl PartialOrd<$SignedInnerT> for $SelfT {
310 fn partial_cmp(&self, other: &$SignedInnerT) -> Option<Ordering> {
311 let lhs = <$SignedInnerT>::from(*self);
312 Some(lhs.cmp(other))
313 }
314 }
315
316 impl Ord for $SelfT {
317 fn cmp(&self, other: &$SelfT) -> Ordering {
318 let lhs = <$SignedInnerT>::from(*self);
320 let rhs = <$SignedInnerT>::from(*other);
321 lhs.cmp(&rhs)
322 }
323 }
324
325 impl WordCommon for $SelfT {
326 fn signum(&self) -> Signum {
327 if self.is_zero() {
328 Signum::Zero
329 } else if self.is_negative() {
330 Signum::Negative
331 } else {
332 Signum::Positive
333 }
334 }
335 }
336 };
337}
338
339#[derive(Clone, Copy)]
347pub struct Signed5Bit {
348 pub(crate) bits: u8,
349}
350
351signed_ones_complement_impl!(Signed5Bit, 5, u8, i8, Unsigned5Bit);
352
353try_from_native_type_to_self!(Signed5Bit, u8, i8, i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
355
356from_self_to_native_type!(Signed5Bit, u8, i8, i8 i16 i32 i64 isize);
357try_from_self_to_native_type!(Signed5Bit, u8, i8, u8 u16 u32 u64 usize);
358
359#[derive(Clone, Copy)]
367pub struct Signed6Bit {
368 pub(crate) bits: u8,
369}
370
371signed_ones_complement_impl!(Signed6Bit, 6, u8, i8, Unsigned6Bit);
372
373try_from_native_type_to_self!(Signed6Bit, u8, i8, i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
375
376from_self_to_native_type!(Signed6Bit, u8, i8, i8 i16 i32 i64 isize);
377try_from_self_to_native_type!(Signed6Bit, u8, i8, u8 u16 u32 u64 usize);
378
379#[derive(Clone, Copy)]
385pub struct Signed9Bit {
386 pub(crate) bits: u16,
387}
388
389signed_ones_complement_impl!(Signed9Bit, 9, u16, i16, Unsigned9Bit);
390
391from_native_type_to_self!(Signed9Bit, u16, i16, i8 u8);
392try_from_native_type_to_self!(Signed9Bit, u16, i16, i16 u16 i32 u32 i64 u64 isize usize);
393
394from_self_to_native_type!(Signed9Bit, u16, i16, i16 i32 i64 isize);
395try_from_self_to_native_type!(Signed9Bit, u16, i16, i8 u8 u16 u32 u64 usize);
396
397#[derive(Clone, Copy)]
403pub struct Signed12Bit {
404 pub(crate) bits: u16,
405}
406
407signed_ones_complement_impl!(Signed12Bit, 12, u16, i16, Unsigned12Bit);
408
409from_native_type_to_self!(Signed12Bit, u16, i16, i8 u8);
410try_from_native_type_to_self!(Signed12Bit, u16, i16, i16 u16 i32 u32 i64 u64 isize usize);
411
412from_self_to_native_type!(Signed12Bit, u16, i16, i16 i32 i64 isize);
413try_from_self_to_native_type!(Signed12Bit, u16, i16, i8 u8 u16 u32 u64);
414
415#[derive(Clone, Copy)]
421pub struct Signed18Bit {
422 pub(crate) bits: u32,
423}
424
425signed_ones_complement_impl!(Signed18Bit, 18, u32, i32, Unsigned18Bit);
426
427from_native_type_to_self!(Signed18Bit, u32, i32, i8 u8 i16 u16);
428try_from_native_type_to_self!(Signed18Bit, u32, i32, i32 u32 i64 u64 isize usize);
429
430from_self_to_native_type!(Signed18Bit, u32, i32, i32 i64 isize);
431try_from_self_to_native_type!(Signed18Bit, u32, i32, i8 u8 i16 u16 u32 u64 usize);
432
433#[derive(Clone, Copy)]
439pub struct Signed36Bit {
440 pub(crate) bits: u64,
441}
442
443signed_ones_complement_impl!(Signed36Bit, 36, u64, i64, Unsigned36Bit);
444
445from_native_type_to_self!(Signed36Bit, u64, i64, i8 u8 i16 u16 i32 u32);
446try_from_native_type_to_self!(Signed36Bit, u64, i64, i64 u64 isize usize);
447
448from_self_to_native_type!(Signed36Bit, u64, i64, i64);
449try_from_self_to_native_type!(Signed36Bit, u64, i64, i8 u8 i16 u16 i32 u32 u64 isize usize);
450
451impl TryFrom<Unsigned18Bit> for Signed18Bit {
452 type Error = ConversionFailed;
453 fn try_from(n: Unsigned18Bit) -> Result<Self, ConversionFailed> {
454 let val: i32 = i32::from(n);
455 Signed18Bit::try_from(val)
456 }
457}
458
459impl From<Signed5Bit> for Signed18Bit {
460 fn from(n: Signed5Bit) -> Self {
461 Signed18Bit::from(i8::from(n))
462 }
463}
464
465impl From<Signed6Bit> for Signed18Bit {
466 fn from(n: Signed6Bit) -> Self {
467 Signed18Bit::from(i8::from(n))
468 }
469}
470
471impl From<Signed9Bit> for Signed18Bit {
472 fn from(n: Signed9Bit) -> Self {
473 Signed18Bit::from(i16::from(n))
474 }
475}