1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use num_traits::{abs, one, zero, Signed};
use platform_num::{LinkType, ToSigned};

#[derive(Debug, Clone, Copy, Hash, PartialOrd, PartialEq, Ord, Eq)]
pub struct Hybrid<T: LinkType> {
    value: T,
}

impl<T: LinkType> Hybrid<T> {
    pub fn new(value: T) -> Self {
        Self::internal(value)
    }

    pub fn external(value: T) -> Self {
        Self {
            value: Self::extend_value(value),
        }
    }

    pub fn internal(value: T) -> Self {
        Self { value }
    }

    fn extend_value(value: T) -> T {
        if value == zero() {
            Self::external_zero()
        } else {
            T::MAX - value + one()
        }
    }

    pub fn half() -> T {
        T::MAX / T::from_u8(2).unwrap()
    }

    pub fn external_zero() -> T {
        Self::half() - one()
    }

    pub fn is_nothing(&self) -> bool {
        self.value == Self::external_zero() || self.signed() == zero()
    }

    pub fn is_internal(&self) -> bool {
        self.signed() > zero()
    }

    pub fn is_external(&self) -> bool {
        self.value == Self::external_zero() || self.signed() < zero()
    }

    pub fn signed(&self) -> <T as ToSigned>::Type {
        self.value.to_signed()
    }

    pub fn absolute(&self) -> T {
        let abs = if self.value == Self::external_zero() {
            zero()
        } else {
            abs(self.signed())
        }
        .abs();
        T::from(abs).unwrap()
    }

    pub fn as_value(&self) -> T {
        self.value
    }
}