1use std::rc::Rc;
2use std::i64;
3
4use owning_ref::OwningRef;
5
6use vars::{VarRef, Variable};
7
8#[derive(Debug)] pub 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}