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
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use crate::interval::*;
use std::convert::TryFrom;

macro_rules! impl_to_bytes {
    ($to_xe_bytes:ident) => {
        pub fn $to_xe_bytes(self) -> [u8; 16] {
            let mut bytes = [0u8; 16];
            bytes[..8].copy_from_slice(&f64::$to_xe_bytes(self.inf()));
            bytes[8..16].copy_from_slice(&f64::$to_xe_bytes(self.sup()));
            bytes
        }
    };
}

macro_rules! impl_try_from_bytes {
    ($try_from_xe_bytes:ident, $from_xe_bytes:ident) => {
        pub fn $try_from_xe_bytes(bytes: [u8; 16]) -> Result<Self> {
            let a = f64::$from_xe_bytes(<[u8; 8]>::try_from(&bytes[..8]).unwrap());
            let b = f64::$from_xe_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap());
            if a <= b
                && a != f64::INFINITY
                && b != f64::NEG_INFINITY
                && (a != 0.0 || a.is_sign_negative())
                && (b != 0.0 || b.is_sign_positive())
            {
                Ok(Self::with_infsup_raw(a, b))
            } else {
                Err(IntervalError {
                    kind: IntervalErrorKind::UndefinedOperation,
                    value: Self::EMPTY,
                })
            }
        }
    };
}

impl Interval {
    impl_to_bytes!(to_be_bytes);
    impl_to_bytes!(to_le_bytes);
    impl_to_bytes!(to_ne_bytes);

    impl_try_from_bytes!(try_from_be_bytes, from_be_bytes);
    impl_try_from_bytes!(try_from_le_bytes, from_le_bytes);
    impl_try_from_bytes!(try_from_ne_bytes, from_ne_bytes);
}

macro_rules! impl_to_bytes {
    ($to_xe_bytes:ident) => {
        pub fn $to_xe_bytes(self) -> [u8; 17] {
            let mut bytes = [0u8; 17];
            bytes[..8].copy_from_slice(&f64::$to_xe_bytes(self.inf()));
            bytes[8..16].copy_from_slice(&f64::$to_xe_bytes(self.sup()));
            bytes[16] = self.d as u8;
            bytes
        }
    };
}

macro_rules! impl_try_from_bytes {
    ($try_from_xe_bytes:ident, $from_xe_bytes:ident) => {
        pub fn $try_from_xe_bytes(bytes: [u8; 17]) -> Result<Self> {
            let a = f64::$from_xe_bytes(<[u8; 8]>::try_from(&bytes[..8]).unwrap());
            let b = f64::$from_xe_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap());

            if a.is_nan() && b.is_nan() && bytes[16] == 0 {
                return Ok(Self::NAI);
            }

            if let (true, Some(d)) = (
                a <= b
                    && a != f64::INFINITY
                    && b != f64::NEG_INFINITY
                    && (a != 0.0 || a.is_sign_negative())
                    && (b != 0.0 || b.is_sign_positive()),
                match bytes[16] {
                    4 => Some(Decoration::Trv),
                    8 => Some(Decoration::Def),
                    12 => Some(Decoration::Dac),
                    16 if a != f64::NEG_INFINITY && b != f64::INFINITY => Some(Decoration::Com),
                    _ => None,
                },
            ) {
                Ok(Self::new_unchecked(Interval::with_infsup_raw(a, b), d))
            } else {
                Err(IntervalError {
                    kind: IntervalErrorKind::UndefinedOperation,
                    value: Self::NAI,
                })
            }
        }
    };
}

impl DecoratedInterval {
    impl_to_bytes!(to_be_bytes);
    impl_to_bytes!(to_le_bytes);
    impl_to_bytes!(to_ne_bytes);

    impl_try_from_bytes!(try_from_be_bytes, from_be_bytes);
    impl_try_from_bytes!(try_from_le_bytes, from_le_bytes);
    impl_try_from_bytes!(try_from_ne_bytes, from_ne_bytes);
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{const_dec_interval, const_interval};
    type D = Decoration;
    type DI = DecoratedInterval;
    type I = Interval;

    #[test]
    fn interval() {
        fn test_roundtrip(x: I) {
            assert_eq!(I::try_from_be_bytes(x.to_be_bytes()).unwrap(), x);
            assert_eq!(I::try_from_le_bytes(x.to_le_bytes()).unwrap(), x);
            assert_eq!(I::try_from_ne_bytes(x.to_ne_bytes()).unwrap(), x);
        }

        test_roundtrip(const_interval!(-0.0, 0.0));
        test_roundtrip(const_interval!(-1.0, 3.0));
        test_roundtrip(const_interval!(f64::NEG_INFINITY, f64::INFINITY));

        fn make_bytes(a: f64, b: f64) -> [u8; 16] {
            let mut bytes = [0u8; 16];
            bytes[..8].copy_from_slice(&f64::to_ne_bytes(a));
            bytes[8..16].copy_from_slice(&f64::to_ne_bytes(b));
            bytes
        }

        assert!(I::try_from_ne_bytes(make_bytes(3.0, -1.0)).is_err());
        assert!(I::try_from_ne_bytes(make_bytes(f64::INFINITY, f64::INFINITY)).is_err());
        assert!(I::try_from_ne_bytes(make_bytes(f64::NEG_INFINITY, f64::NEG_INFINITY)).is_err());
        assert!(I::try_from_ne_bytes(make_bytes(0.0, 0.0)).is_err());
        assert!(I::try_from_ne_bytes(make_bytes(-0.0, -0.0)).is_err());
    }

    #[test]
    fn dec_interval() {
        fn test_roundtrip(x: DI) {
            let y = DI::try_from_be_bytes(x.to_be_bytes()).unwrap();
            assert!(x.is_nai() && y.is_nai() || x == y);
            let y = DI::try_from_le_bytes(x.to_le_bytes()).unwrap();
            assert!(x.is_nai() && y.is_nai() || x == y);
            let y = DI::try_from_ne_bytes(x.to_ne_bytes()).unwrap();
            assert!(x.is_nai() && y.is_nai() || x == y);
        }

        test_roundtrip(const_dec_interval!(-0.0, 0.0));
        test_roundtrip(const_dec_interval!(-1.0, 3.0));
        test_roundtrip(DI::set_dec(
            const_interval!(f64::NEG_INFINITY, f64::INFINITY),
            D::Trv,
        ));
        test_roundtrip(DI::set_dec(
            const_interval!(f64::NEG_INFINITY, f64::INFINITY),
            D::Def,
        ));
        test_roundtrip(DI::set_dec(
            const_interval!(f64::NEG_INFINITY, f64::INFINITY),
            D::Dac,
        ));
        test_roundtrip(DI::NAI);

        fn make_bytes(a: f64, b: f64, d: D) -> [u8; 17] {
            let mut bytes = [0u8; 17];
            bytes[..8].copy_from_slice(&f64::to_ne_bytes(a));
            bytes[8..16].copy_from_slice(&f64::to_ne_bytes(b));
            bytes[16] = d as u8;
            bytes
        }

        assert!(DI::try_from_ne_bytes(make_bytes(3.0, -1.0, D::Trv)).is_err());
        assert!(DI::try_from_ne_bytes(make_bytes(f64::INFINITY, f64::INFINITY, D::Trv)).is_err());
        assert!(
            DI::try_from_ne_bytes(make_bytes(f64::NEG_INFINITY, f64::NEG_INFINITY, D::Trv))
                .is_err()
        );
        assert!(DI::try_from_ne_bytes(make_bytes(0.0, 0.0, D::Trv)).is_err());
        assert!(DI::try_from_ne_bytes(make_bytes(-0.0, -0.0, D::Trv)).is_err());

        assert!(DI::try_from_ne_bytes(make_bytes(-1.0, f64::NAN, D::Ill)).is_err());
        assert!(DI::try_from_ne_bytes(make_bytes(f64::NAN, 3.0, D::Ill)).is_err());

        assert!(DI::try_from_ne_bytes(make_bytes(f64::NEG_INFINITY, 3.0, D::Com)).is_err());
        assert!(DI::try_from_ne_bytes(make_bytes(-1.0, f64::INFINITY, D::Com)).is_err());
    }
}