base/onescomplement/
signed.rs

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
20// This macro implements conversions from native types to Unsigned*Bit
21// which are always possible (e.g. From<i8> for Signed9Bit).
22macro_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
64// This macro implements conversions from Unsigned*Bit to native types
65// which are always possible (e.g. From<Signed9Bit> for i16).
66macro_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
86// This macro implements conversions from Unsigned*Bit to native types
87// which may not always be possible (e.g. From<Signed18Bit> for u16).
88macro_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                    // -0 should hash to the same value as +0.
275                    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                // We perform conversion here so that -0 == +0.
319                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////////////////////////////////////////////////////////////////////////
340// Signed5Bit
341////////////////////////////////////////////////////////////////////////
342
343/// `Signed5Bit` is somewhat special-purpose for instructions such as
344/// JPX which use the instruction's configuration value as a 5-bit
345/// signed integer.
346#[derive(Clone, Copy)]
347pub struct Signed5Bit {
348    pub(crate) bits: u8,
349}
350
351signed_ones_complement_impl!(Signed5Bit, 5, u8, i8, Unsigned5Bit);
352
353// from_native_type_to_self: nothing is narrow enough to always succeed.
354try_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////////////////////////////////////////////////////////////////////////
360// Signed6Bit
361////////////////////////////////////////////////////////////////////////
362
363/// `Signed6Bit` is somewhat special-purpose as the signed counterpart
364/// for `Unsigned6Bit`, which is for handlng index register numbers and
365/// sequence numbers.
366#[derive(Clone, Copy)]
367pub struct Signed6Bit {
368    pub(crate) bits: u8,
369}
370
371signed_ones_complement_impl!(Signed6Bit, 6, u8, i8, Unsigned6Bit);
372
373// from_native_type_to_self: nothing is narrow enough to always succeed.
374try_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////////////////////////////////////////////////////////////////////////
380// Signed9Bit
381////////////////////////////////////////////////////////////////////////
382
383/// Signed counterpart of [`Unsigned9Bit`].
384#[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////////////////////////////////////////////////////////////////////////
398// Signed12Bit
399////////////////////////////////////////////////////////////////////////
400
401/// Signed counterpart of [`Unsigned12Bit`].
402#[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////////////////////////////////////////////////////////////////////////
416// Signed18Bit
417////////////////////////////////////////////////////////////////////////
418
419/// Signed counterpart of [`Unsigned18Bit`].
420#[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////////////////////////////////////////////////////////////////////////
434// Signed36Bit
435////////////////////////////////////////////////////////////////////////
436
437/// Signed counterpart of [`Unsigned36Bit`].
438#[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}