trimmer/
number.rs

1use std::rc::Rc;
2use std::i64;
3
4use owning_ref::OwningRef;
5
6use vars::{VarRef, Variable};
7
8/// An internal representation of a number that may be integer of real
9///
10/// Use `into()` conversion to make the value.
11#[derive(Debug)]  // TODO(tailhook) make normal debug
12pub struct Number(NumberInner);
13
14#[derive(Clone, Copy, Debug)]
15enum NumberInner {
16    I64(i64),
17    U64(u64),
18    F64(f64),
19}
20
21impl From<i8> for Number {
22    fn from(x: i8) -> Number {
23        Number(NumberInner::I64(x as i64))
24    }
25}
26
27impl From<i16> for Number {
28    fn from(x: i16) -> Number {
29        Number(NumberInner::I64(x as i64))
30    }
31}
32
33impl From<i32> for Number {
34    fn from(x: i32) -> Number {
35        Number(NumberInner::I64(x as i64))
36    }
37}
38
39impl From<i64> for Number {
40    fn from(x: i64) -> Number {
41        Number(NumberInner::I64(x))
42    }
43}
44
45impl From<u8> for Number {
46    fn from(x: u8) -> Number {
47        Number(NumberInner::U64(x as u64))
48    }
49}
50
51impl From<u16> for Number {
52    fn from(x: u16) -> Number {
53        Number(NumberInner::U64(x as u64))
54    }
55}
56
57impl From<u32> for Number {
58    fn from(x: u32) -> Number {
59        Number(NumberInner::U64(x as u64))
60    }
61}
62
63impl From<u64> for Number {
64    fn from(x: u64) -> Number {
65        Number(NumberInner::U64(x))
66    }
67}
68
69#[cfg(target_pointer_width="64")]
70impl From<usize> for Number {
71    fn from(x: usize) -> Number {
72        Number(NumberInner::U64(x as u64))
73    }
74}
75
76#[cfg(target_pointer_width="32")]
77impl From<usize> for Number {
78    fn from(x: usize) -> Number {
79        Number(NumberInner::U32(x as u32))
80    }
81}
82
83#[cfg(target_pointer_width="64")]
84impl From<isize> for Number {
85    fn from(x: isize) -> Number {
86        Number(NumberInner::I64(x as i64))
87    }
88}
89
90#[cfg(target_pointer_width="32")]
91impl From<isize> for Number {
92    fn from(x: isize) -> Number {
93        Number(NumberInner::I32(x as i32))
94    }
95}
96
97impl From<f32> for Number {
98    fn from(x: f32) -> Number {
99        Number(NumberInner::F64(x as f64))
100    }
101}
102
103impl From<f64> for Number {
104    fn from(x: f64) -> Number {
105        Number(NumberInner::F64(x))
106    }
107}
108
109fn val<'x, T: Variable<'x>+'x>(v: T) -> VarRef<'x> {
110    OwningRef::new(Rc::new(v)).map(|x| x as &Variable).erase_owner()
111}
112
113fn norm(n: NumberInner) -> NumberInner {
114    use self::NumberInner::*;
115    match n {
116        I64(a) if a > 0 => U64(a as u64),
117        n => n,
118    }
119}
120
121pub fn add<'x>(a: Number, b: Number) -> VarRef<'x> {
122    use self::NumberInner::*;
123    match (norm(a.0), norm(b.0)) {
124        (I64(a), I64(b)) => {
125            a.checked_add(b).map(val)
126            .unwrap_or_else(|| val((a as f64) + (b as f64)))
127        }
128        (U64(a), U64(b)) => {
129            a.checked_add(b).map(val)
130            .unwrap_or_else(|| val((a as f64) + (b as f64)))
131        }
132        (F64(a), F64(b)) => val(a + b),
133        (I64(a), F64(b)) => val(a as f64 + b),
134        (F64(a), I64(b)) => val(a + b as f64),
135        (U64(a), F64(b)) => val(a as f64 + b),
136        (F64(a), U64(b)) => val(a + b as f64),
137        (I64(a), U64(b)) | (U64(b), I64(a)) => {
138            b.checked_sub((-a as u64)).map(val)
139            .or_else(|| (-a as u64).checked_sub(b).map(|x| val(-(x as i64))))
140            .unwrap_or_else(|| val((a as f64) + (b as f64)))
141        }
142    }
143}
144
145pub fn sub<'x>(a: Number, b: Number) -> VarRef<'x> {
146    use self::NumberInner::*;
147    match (norm(a.0), norm(b.0)) {
148        (I64(a), I64(b)) => {
149            a.checked_sub(b).map(val)
150            .unwrap_or_else(|| val((a as f64) - (b as f64)))
151        }
152        (U64(a), U64(b)) => {
153            a.checked_sub(b).map(val)
154            .unwrap_or_else(|| val((a as f64) - (b as f64)))
155        }
156        (F64(a), F64(b)) => val(a - b),
157        (I64(a), F64(b)) => val(a as f64 - b),
158        (F64(a), I64(b)) => val(a - b as f64),
159        (U64(a), F64(b)) => val(a as f64 - b),
160        (F64(a), U64(b)) => val(a - b as f64),
161        (U64(a), I64(b)) => {
162            a.checked_add((-b as u64)).map(val)
163            .unwrap_or_else(|| val((a as f64) - (b as f64)))
164        }
165        (I64(a), U64(b)) if b < i64::MAX as u64 => {
166            a.checked_sub(b as i64).map(val)
167            .unwrap_or_else(|| val((a as f64) - (b as f64)))
168        }
169        (I64(a), U64(b)) => val((a as f64) - (b as f64)),
170    }
171}
172
173pub fn mul<'x>(a: Number, b: Number) -> VarRef<'x> {
174    use self::NumberInner::*;
175    match (norm(a.0), norm(b.0)) {
176        (I64(a), I64(b)) => {
177            a.checked_mul(b).map(val)
178            .unwrap_or_else(|| val((a as f64) * (b as f64)))
179        }
180        (U64(a), U64(b)) => {
181            a.checked_mul(b).map(val)
182            .unwrap_or_else(|| val((a as f64) * (b as f64)))
183        }
184        (F64(a), F64(b)) => val(a * b),
185        (I64(a), F64(b)) => val(a as f64 * b),
186        (F64(a), I64(b)) => val(a * b as f64),
187        (U64(a), F64(b)) => val(a as f64 * b),
188        (F64(a), U64(b)) => val(a * b as f64),
189        (U64(a), I64(b)) => val((a as f64) * (b as f64)),
190        (I64(a), U64(b)) => val((a as f64) * (b as f64)),
191    }
192}
193
194pub fn div<'x>(a: Number, b: Number) -> VarRef<'x> {
195    use self::NumberInner::*;
196    match (norm(a.0), norm(b.0)) {
197        (I64(a), I64(b)) => {
198            if a % b == 0 {
199                val(a / b)
200            } else {
201                val((a as f64) / (b as f64))
202            }
203        }
204        (U64(a), U64(b)) => {
205            if a % b == 0 {
206                val(a / b)
207            } else {
208                val((a as f64) / (b as f64))
209            }
210        }
211        (F64(a), F64(b)) => val(a / b),
212        (I64(a), F64(b)) => val(a as f64 / b),
213        (F64(a), I64(b)) => val(a / b as f64),
214        (U64(a), F64(b)) => val(a as f64 / b),
215        (F64(a), U64(b)) => val(a / b as f64),
216        (U64(a), I64(b)) => val((a as f64) / (b as f64)),
217        (I64(a), U64(b)) => val((a as f64) / (b as f64)),
218    }
219}
220
221pub fn modulo<'x>(a: Number, b: Number) -> VarRef<'x> {
222    use self::NumberInner::*;
223    match (norm(a.0), norm(b.0)) {
224        (I64(a), I64(b)) => val(a % b),
225        (U64(a), U64(b)) => val(a % b),
226        (F64(a), F64(b)) => val(a % b),
227        (I64(a), F64(b)) => val(a as f64 % b),
228        (F64(a), I64(b)) => val(a % b as f64),
229        (U64(a), F64(b)) => val(a as f64 % b),
230        (F64(a), U64(b)) => val(a % b as f64),
231        (U64(a), I64(b)) => val((a as f64) % (b as f64)),
232        (I64(a), U64(b)) => val((a as f64) % (b as f64)),
233    }
234}