]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use std::cmp::Ordering; | |
12 | use syntax::attr::IntType; | |
13 | use syntax::ast::{IntTy, UintTy}; | |
14 | ||
15 | use super::is::*; | |
16 | use super::us::*; | |
17 | use super::err::*; | |
18 | ||
19 | #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)] | |
20 | pub enum ConstInt { | |
21 | I8(i8), | |
22 | I16(i16), | |
23 | I32(i32), | |
24 | I64(i64), | |
32a655c1 | 25 | I128(i128), |
54a0048b SL |
26 | Isize(ConstIsize), |
27 | U8(u8), | |
28 | U16(u16), | |
29 | U32(u32), | |
30 | U64(u64), | |
32a655c1 | 31 | U128(u128), |
54a0048b | 32 | Usize(ConstUsize), |
54a0048b SL |
33 | } |
34 | pub use self::ConstInt::*; | |
35 | ||
36 | ||
37 | macro_rules! bounds { | |
32a655c1 SL |
38 | ($ct: ty, $($t:ident $min:ident $max:ident)*) => { |
39 | $( | |
40 | pub const $min: $ct = $t::min_value() as $ct; | |
41 | pub const $max: $ct = $t::max_value() as $ct; | |
42 | )* | |
43 | }; | |
44 | ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => { | |
45 | $( | |
46 | pub const $min: $ct = $min_val; | |
47 | pub const $max: $ct = $t::max_value() as $ct; | |
48 | )* | |
49 | } | |
50 | } | |
51 | ||
52 | mod ubounds { | |
53 | #![allow(dead_code)] | |
32a655c1 SL |
54 | bounds!{u128: 0, |
55 | i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX | |
56 | u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX | |
57 | // do not add constants for isize/usize, because these are guaranteed to be wrong for | |
58 | // arbitrary host/target combinations | |
54a0048b SL |
59 | } |
60 | } | |
61 | ||
32a655c1 SL |
62 | mod ibounds { |
63 | #![allow(dead_code)] | |
32a655c1 SL |
64 | bounds!(i128, u64 U64MIN U64MAX); |
65 | ||
66 | pub const U128MIN: i128 = 0; | |
67 | pub const U128MAX: i128 = i128::max_value(); | |
68 | ||
69 | bounds!{i128, | |
70 | i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX | |
71 | u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX | |
72 | // do not add constants for isize/usize, because these are guaranteed to be wrong for | |
73 | // arbitrary host/target combinations | |
74 | } | |
54a0048b SL |
75 | } |
76 | ||
77 | impl ConstInt { | |
32a655c1 SL |
78 | /// Creates a new unsigned ConstInt with matching type while also checking that overflow does |
79 | /// not happen. | |
80 | pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> { | |
81 | match ty { | |
82 | UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)), | |
83 | UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)), | |
84 | UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)), | |
85 | UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)), | |
86 | UintTy::Us if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok() | |
87 | .map(Usize), | |
88 | UintTy::U128 => Some(U128(val)), | |
89 | _ => None | |
90 | } | |
91 | } | |
92 | ||
8bb4bdeb | 93 | /// Creates a new signed ConstInt with matching type while also checking that overflow does |
32a655c1 SL |
94 | /// not happen. |
95 | pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> { | |
96 | match ty { | |
97 | IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)), | |
98 | IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)), | |
99 | IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)), | |
100 | IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)), | |
101 | IntTy::Is if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok() | |
102 | .map(Isize), | |
103 | IntTy::I128 => Some(I128(val)), | |
104 | _ => None | |
105 | } | |
106 | } | |
107 | ||
8bb4bdeb XL |
108 | /// Creates a new unsigned ConstInt with matching type. |
109 | pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt { | |
110 | match ty { | |
111 | UintTy::U8 => U8(val as u8), | |
112 | UintTy::U16 => U16(val as u16), | |
113 | UintTy::U32 => U32(val as u32), | |
114 | UintTy::U64 => U64(val as u64), | |
115 | UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)), | |
116 | UintTy::U128 => U128(val) | |
117 | } | |
54a0048b SL |
118 | } |
119 | ||
8bb4bdeb XL |
120 | /// Creates a new signed ConstInt with matching type. |
121 | pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt { | |
122 | match ty { | |
123 | IntTy::I8 => I8(val as i8), | |
124 | IntTy::I16 => I16(val as i16), | |
125 | IntTy::I32 => I32(val as i32), | |
126 | IntTy::I64 => I64(val as i64), | |
127 | IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)), | |
128 | IntTy::I128 => I128(val) | |
54a0048b SL |
129 | } |
130 | } | |
131 | ||
132 | /// Description of the type, not the value | |
133 | pub fn description(&self) -> &'static str { | |
134 | match *self { | |
54a0048b SL |
135 | I8(_) => "i8", |
136 | I16(_) => "i16", | |
137 | I32(_) => "i32", | |
138 | I64(_) => "i64", | |
32a655c1 | 139 | I128(_) => "i128", |
54a0048b SL |
140 | Isize(_) => "isize", |
141 | U8(_) => "u8", | |
142 | U16(_) => "u16", | |
143 | U32(_) => "u32", | |
144 | U64(_) => "u64", | |
32a655c1 | 145 | U128(_) => "u128", |
54a0048b SL |
146 | Usize(_) => "usize", |
147 | } | |
148 | } | |
149 | ||
32a655c1 SL |
150 | /// Erases the type and returns a u128. |
151 | /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128` | |
152 | pub fn to_u128_unchecked(self) -> u128 { | |
8bb4bdeb XL |
153 | match self { |
154 | I8(i) => i as i128 as u128, | |
155 | I16(i) => i as i128 as u128, | |
156 | I32(i) => i as i128 as u128, | |
157 | I64(i) => i as i128 as u128, | |
158 | I128(i) => i as i128 as u128, | |
159 | Isize(Is16(i)) => i as i128 as u128, | |
160 | Isize(Is32(i)) => i as i128 as u128, | |
161 | Isize(Is64(i)) => i as i128 as u128, | |
162 | U8(i) => i as u128, | |
163 | U16(i) => i as u128, | |
164 | U32(i) => i as u128, | |
165 | U64(i) => i as u128, | |
166 | U128(i) => i as u128, | |
167 | Usize(Us16(i)) => i as u128, | |
168 | Usize(Us32(i)) => i as u128, | |
169 | Usize(Us64(i)) => i as u128, | |
54a0048b SL |
170 | } |
171 | } | |
172 | ||
173 | /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX | |
174 | pub fn to_u32(&self) -> Option<u32> { | |
32a655c1 SL |
175 | self.to_u128().and_then(|v| if v <= u32::max_value() as u128 { |
176 | Some(v as u32) | |
177 | } else { | |
178 | None | |
179 | }) | |
54a0048b SL |
180 | } |
181 | ||
32a655c1 | 182 | /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX |
54a0048b | 183 | pub fn to_u64(&self) -> Option<u64> { |
32a655c1 SL |
184 | self.to_u128().and_then(|v| if v <= u64::max_value() as u128 { |
185 | Some(v as u64) | |
186 | } else { | |
187 | None | |
188 | }) | |
189 | } | |
190 | ||
191 | /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX | |
192 | pub fn to_u128(&self) -> Option<u128> { | |
54a0048b | 193 | match *self { |
32a655c1 SL |
194 | I8(v) if v >= 0 => Some(v as u128), |
195 | I16(v) if v >= 0 => Some(v as u128), | |
196 | I32(v) if v >= 0 => Some(v as u128), | |
197 | I64(v) if v >= 0 => Some(v as u128), | |
198 | I128(v) if v >= 0 => Some(v as u128), | |
199 | Isize(Is16(v)) if v >= 0 => Some(v as u128), | |
200 | Isize(Is32(v)) if v >= 0 => Some(v as u128), | |
201 | Isize(Is64(v)) if v >= 0 => Some(v as u128), | |
202 | U8(v) => Some(v as u128), | |
203 | U16(v) => Some(v as u128), | |
204 | U32(v) => Some(v as u128), | |
205 | U64(v) => Some(v as u128), | |
206 | U128(v) => Some(v as u128), | |
207 | Usize(Us16(v)) => Some(v as u128), | |
208 | Usize(Us32(v)) => Some(v as u128), | |
209 | Usize(Us64(v)) => Some(v as u128), | |
54a0048b SL |
210 | _ => None, |
211 | } | |
212 | } | |
213 | ||
8bb4bdeb XL |
214 | pub fn to_f32(self) -> f32 { |
215 | match self { | |
216 | I8(i) => i as f32, | |
217 | I16(i) => i as f32, | |
218 | I32(i) => i as f32, | |
219 | I64(i) => i as f32, | |
220 | I128(i) => i as f32, | |
221 | Isize(Is16(i)) => i as f32, | |
222 | Isize(Is32(i)) => i as f32, | |
223 | Isize(Is64(i)) => i as f32, | |
224 | U8(i) => i as f32, | |
225 | U16(i) => i as f32, | |
226 | U32(i) => i as f32, | |
227 | U64(i) => i as f32, | |
228 | U128(i) => i as f32, | |
229 | Usize(Us16(i)) => i as f32, | |
230 | Usize(Us32(i)) => i as f32, | |
231 | Usize(Us64(i)) => i as f32, | |
232 | } | |
233 | } | |
234 | ||
235 | pub fn to_f64(self) -> f64 { | |
236 | match self { | |
237 | I8(i) => i as f64, | |
238 | I16(i) => i as f64, | |
239 | I32(i) => i as f64, | |
240 | I64(i) => i as f64, | |
241 | I128(i) => i as f64, | |
242 | Isize(Is16(i)) => i as f64, | |
243 | Isize(Is32(i)) => i as f64, | |
244 | Isize(Is64(i)) => i as f64, | |
245 | U8(i) => i as f64, | |
246 | U16(i) => i as f64, | |
247 | U32(i) => i as f64, | |
248 | U64(i) => i as f64, | |
249 | U128(i) => i as f64, | |
250 | Usize(Us16(i)) => i as f64, | |
251 | Usize(Us32(i)) => i as f64, | |
252 | Usize(Us64(i)) => i as f64, | |
253 | } | |
254 | } | |
255 | ||
54a0048b SL |
256 | pub fn is_negative(&self) -> bool { |
257 | match *self { | |
258 | I8(v) => v < 0, | |
259 | I16(v) => v < 0, | |
260 | I32(v) => v < 0, | |
261 | I64(v) => v < 0, | |
32a655c1 | 262 | I128(v) => v < 0, |
3157f602 | 263 | Isize(Is16(v)) => v < 0, |
54a0048b SL |
264 | Isize(Is32(v)) => v < 0, |
265 | Isize(Is64(v)) => v < 0, | |
54a0048b SL |
266 | _ => false, |
267 | } | |
268 | } | |
269 | ||
270 | /// Compares the values if they are of the same type | |
271 | pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> { | |
8bb4bdeb | 272 | match (self, rhs) { |
54a0048b SL |
273 | (I8(a), I8(b)) => Ok(a.cmp(&b)), |
274 | (I16(a), I16(b)) => Ok(a.cmp(&b)), | |
275 | (I32(a), I32(b)) => Ok(a.cmp(&b)), | |
276 | (I64(a), I64(b)) => Ok(a.cmp(&b)), | |
32a655c1 | 277 | (I128(a), I128(b)) => Ok(a.cmp(&b)), |
3157f602 | 278 | (Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)), |
54a0048b SL |
279 | (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)), |
280 | (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)), | |
281 | (U8(a), U8(b)) => Ok(a.cmp(&b)), | |
282 | (U16(a), U16(b)) => Ok(a.cmp(&b)), | |
283 | (U32(a), U32(b)) => Ok(a.cmp(&b)), | |
284 | (U64(a), U64(b)) => Ok(a.cmp(&b)), | |
32a655c1 | 285 | (U128(a), U128(b)) => Ok(a.cmp(&b)), |
3157f602 | 286 | (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)), |
54a0048b SL |
287 | (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)), |
288 | (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)), | |
54a0048b SL |
289 | _ => Err(CmpBetweenUnequalTypes), |
290 | } | |
291 | } | |
292 | ||
293 | /// Adds 1 to the value and wraps around if the maximum for the type is reached | |
294 | pub fn wrap_incr(self) -> Self { | |
295 | macro_rules! add1 { | |
296 | ($e:expr) => { ($e).wrapping_add(1) } | |
297 | } | |
298 | match self { | |
299 | ConstInt::I8(i) => ConstInt::I8(add1!(i)), | |
300 | ConstInt::I16(i) => ConstInt::I16(add1!(i)), | |
301 | ConstInt::I32(i) => ConstInt::I32(add1!(i)), | |
302 | ConstInt::I64(i) => ConstInt::I64(add1!(i)), | |
32a655c1 | 303 | ConstInt::I128(i) => ConstInt::I128(add1!(i)), |
3157f602 | 304 | ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))), |
54a0048b SL |
305 | ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))), |
306 | ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))), | |
307 | ConstInt::U8(i) => ConstInt::U8(add1!(i)), | |
308 | ConstInt::U16(i) => ConstInt::U16(add1!(i)), | |
309 | ConstInt::U32(i) => ConstInt::U32(add1!(i)), | |
310 | ConstInt::U64(i) => ConstInt::U64(add1!(i)), | |
32a655c1 | 311 | ConstInt::U128(i) => ConstInt::U128(add1!(i)), |
3157f602 | 312 | ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))), |
54a0048b SL |
313 | ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))), |
314 | ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))), | |
54a0048b SL |
315 | } |
316 | } | |
317 | ||
8bb4bdeb | 318 | pub fn int_type(self) -> IntType { |
54a0048b | 319 | match self { |
8bb4bdeb XL |
320 | ConstInt::I8(_) => IntType::SignedInt(IntTy::I8), |
321 | ConstInt::I16(_) => IntType::SignedInt(IntTy::I16), | |
322 | ConstInt::I32(_) => IntType::SignedInt(IntTy::I32), | |
323 | ConstInt::I64(_) => IntType::SignedInt(IntTy::I64), | |
324 | ConstInt::I128(_) => IntType::SignedInt(IntTy::I128), | |
325 | ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is), | |
326 | ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8), | |
327 | ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16), | |
328 | ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32), | |
329 | ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64), | |
330 | ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128), | |
331 | ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us), | |
54a0048b SL |
332 | } |
333 | } | |
334 | } | |
335 | ||
336 | impl ::std::cmp::PartialOrd for ConstInt { | |
337 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
338 | self.try_cmp(*other).ok() | |
339 | } | |
340 | } | |
341 | ||
342 | impl ::std::cmp::Ord for ConstInt { | |
343 | fn cmp(&self, other: &Self) -> Ordering { | |
344 | self.try_cmp(*other).unwrap() | |
345 | } | |
346 | } | |
347 | ||
348 | impl ::std::fmt::Display for ConstInt { | |
349 | fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { | |
350 | match *self { | |
54a0048b SL |
351 | I8(i) => write!(fmt, "{}i8", i), |
352 | I16(i) => write!(fmt, "{}i16", i), | |
353 | I32(i) => write!(fmt, "{}i32", i), | |
354 | I64(i) => write!(fmt, "{}i64", i), | |
32a655c1 | 355 | I128(i) => write!(fmt, "{}i128", i), |
54a0048b SL |
356 | Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i), |
357 | Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i), | |
3157f602 | 358 | Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i), |
54a0048b SL |
359 | U8(i) => write!(fmt, "{}u8", i), |
360 | U16(i) => write!(fmt, "{}u16", i), | |
361 | U32(i) => write!(fmt, "{}u32", i), | |
362 | U64(i) => write!(fmt, "{}u64", i), | |
32a655c1 | 363 | U128(i) => write!(fmt, "{}u128", i), |
54a0048b SL |
364 | Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i), |
365 | Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i), | |
3157f602 | 366 | Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i), |
54a0048b SL |
367 | } |
368 | } | |
369 | } | |
370 | ||
371 | macro_rules! overflowing { | |
372 | ($e:expr, $err:expr) => {{ | |
373 | if $e.1 { | |
374 | return Err(Overflow($err)); | |
375 | } else { | |
376 | $e.0 | |
377 | } | |
378 | }} | |
379 | } | |
380 | ||
381 | macro_rules! impl_binop { | |
382 | ($op:ident, $func:ident, $checked_func:ident) => { | |
383 | impl ::std::ops::$op for ConstInt { | |
384 | type Output = Result<Self, ConstMathErr>; | |
385 | fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
8bb4bdeb | 386 | match (self, rhs) { |
54a0048b SL |
387 | (I8(a), I8(b)) => a.$checked_func(b).map(I8), |
388 | (I16(a), I16(b)) => a.$checked_func(b).map(I16), | |
389 | (I32(a), I32(b)) => a.$checked_func(b).map(I32), | |
390 | (I64(a), I64(b)) => a.$checked_func(b).map(I64), | |
32a655c1 | 391 | (I128(a), I128(b)) => a.$checked_func(b).map(I128), |
3157f602 | 392 | (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize), |
54a0048b SL |
393 | (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize), |
394 | (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize), | |
395 | (U8(a), U8(b)) => a.$checked_func(b).map(U8), | |
396 | (U16(a), U16(b)) => a.$checked_func(b).map(U16), | |
397 | (U32(a), U32(b)) => a.$checked_func(b).map(U32), | |
398 | (U64(a), U64(b)) => a.$checked_func(b).map(U64), | |
32a655c1 | 399 | (U128(a), U128(b)) => a.$checked_func(b).map(U128), |
3157f602 | 400 | (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize), |
54a0048b SL |
401 | (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize), |
402 | (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize), | |
54a0048b SL |
403 | _ => return Err(UnequalTypes(Op::$op)), |
404 | }.ok_or(Overflow(Op::$op)) | |
405 | } | |
406 | } | |
407 | } | |
408 | } | |
409 | ||
410 | macro_rules! derive_binop { | |
411 | ($op:ident, $func:ident) => { | |
412 | impl ::std::ops::$op for ConstInt { | |
413 | type Output = Result<Self, ConstMathErr>; | |
414 | fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
8bb4bdeb | 415 | match (self, rhs) { |
54a0048b SL |
416 | (I8(a), I8(b)) => Ok(I8(a.$func(b))), |
417 | (I16(a), I16(b)) => Ok(I16(a.$func(b))), | |
418 | (I32(a), I32(b)) => Ok(I32(a.$func(b))), | |
419 | (I64(a), I64(b)) => Ok(I64(a.$func(b))), | |
32a655c1 | 420 | (I128(a), I128(b)) => Ok(I128(a.$func(b))), |
3157f602 | 421 | (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))), |
54a0048b SL |
422 | (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))), |
423 | (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))), | |
424 | (U8(a), U8(b)) => Ok(U8(a.$func(b))), | |
425 | (U16(a), U16(b)) => Ok(U16(a.$func(b))), | |
426 | (U32(a), U32(b)) => Ok(U32(a.$func(b))), | |
427 | (U64(a), U64(b)) => Ok(U64(a.$func(b))), | |
32a655c1 | 428 | (U128(a), U128(b)) => Ok(U128(a.$func(b))), |
3157f602 | 429 | (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))), |
54a0048b SL |
430 | (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))), |
431 | (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))), | |
54a0048b SL |
432 | _ => Err(UnequalTypes(Op::$op)), |
433 | } | |
434 | } | |
435 | } | |
436 | } | |
437 | } | |
438 | ||
439 | impl_binop!(Add, add, checked_add); | |
440 | impl_binop!(Sub, sub, checked_sub); | |
441 | impl_binop!(Mul, mul, checked_mul); | |
442 | derive_binop!(BitAnd, bitand); | |
443 | derive_binop!(BitOr, bitor); | |
444 | derive_binop!(BitXor, bitxor); | |
445 | ||
32a655c1 | 446 | const I128_MIN: i128 = ::std::i128::MIN; |
32a655c1 | 447 | |
54a0048b SL |
448 | fn check_division( |
449 | lhs: ConstInt, | |
450 | rhs: ConstInt, | |
451 | op: Op, | |
452 | zerr: ConstMathErr, | |
453 | ) -> Result<(), ConstMathErr> { | |
454 | match (lhs, rhs) { | |
455 | (I8(_), I8(0)) => Err(zerr), | |
456 | (I16(_), I16(0)) => Err(zerr), | |
457 | (I32(_), I32(0)) => Err(zerr), | |
458 | (I64(_), I64(0)) => Err(zerr), | |
32a655c1 | 459 | (I128(_), I128(0)) => Err(zerr), |
3157f602 | 460 | (Isize(_), Isize(Is16(0))) => Err(zerr), |
54a0048b SL |
461 | (Isize(_), Isize(Is32(0))) => Err(zerr), |
462 | (Isize(_), Isize(Is64(0))) => Err(zerr), | |
54a0048b SL |
463 | |
464 | (U8(_), U8(0)) => Err(zerr), | |
465 | (U16(_), U16(0)) => Err(zerr), | |
466 | (U32(_), U32(0)) => Err(zerr), | |
467 | (U64(_), U64(0)) => Err(zerr), | |
32a655c1 | 468 | (U128(_), U128(0)) => Err(zerr), |
3157f602 | 469 | (Usize(_), Usize(Us16(0))) => Err(zerr), |
54a0048b SL |
470 | (Usize(_), Usize(Us32(0))) => Err(zerr), |
471 | (Usize(_), Usize(Us64(0))) => Err(zerr), | |
54a0048b SL |
472 | |
473 | (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)), | |
474 | (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)), | |
475 | (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)), | |
476 | (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)), | |
32a655c1 | 477 | (I128(I128_MIN), I128(-1)) => Err(Overflow(op)), |
3157f602 | 478 | (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)), |
54a0048b SL |
479 | (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)), |
480 | (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)), | |
54a0048b SL |
481 | |
482 | _ => Ok(()), | |
483 | } | |
484 | } | |
485 | ||
486 | impl ::std::ops::Div for ConstInt { | |
487 | type Output = Result<Self, ConstMathErr>; | |
488 | fn div(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
8bb4bdeb | 489 | let (lhs, rhs) = (self, rhs); |
54a0048b SL |
490 | check_division(lhs, rhs, Op::Div, DivisionByZero)?; |
491 | match (lhs, rhs) { | |
492 | (I8(a), I8(b)) => Ok(I8(a/b)), | |
493 | (I16(a), I16(b)) => Ok(I16(a/b)), | |
494 | (I32(a), I32(b)) => Ok(I32(a/b)), | |
495 | (I64(a), I64(b)) => Ok(I64(a/b)), | |
32a655c1 | 496 | (I128(a), I128(b)) => Ok(I128(a/b)), |
3157f602 | 497 | (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))), |
54a0048b SL |
498 | (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))), |
499 | (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))), | |
54a0048b SL |
500 | |
501 | (U8(a), U8(b)) => Ok(U8(a/b)), | |
502 | (U16(a), U16(b)) => Ok(U16(a/b)), | |
503 | (U32(a), U32(b)) => Ok(U32(a/b)), | |
504 | (U64(a), U64(b)) => Ok(U64(a/b)), | |
32a655c1 | 505 | (U128(a), U128(b)) => Ok(U128(a/b)), |
3157f602 | 506 | (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))), |
54a0048b SL |
507 | (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))), |
508 | (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))), | |
54a0048b SL |
509 | |
510 | _ => Err(UnequalTypes(Op::Div)), | |
511 | } | |
512 | } | |
513 | } | |
514 | ||
515 | impl ::std::ops::Rem for ConstInt { | |
516 | type Output = Result<Self, ConstMathErr>; | |
517 | fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
8bb4bdeb | 518 | let (lhs, rhs) = (self, rhs); |
54a0048b SL |
519 | // should INT_MIN%-1 be zero or an error? |
520 | check_division(lhs, rhs, Op::Rem, RemainderByZero)?; | |
521 | match (lhs, rhs) { | |
522 | (I8(a), I8(b)) => Ok(I8(a%b)), | |
523 | (I16(a), I16(b)) => Ok(I16(a%b)), | |
524 | (I32(a), I32(b)) => Ok(I32(a%b)), | |
525 | (I64(a), I64(b)) => Ok(I64(a%b)), | |
32a655c1 | 526 | (I128(a), I128(b)) => Ok(I128(a%b)), |
3157f602 | 527 | (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))), |
54a0048b SL |
528 | (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))), |
529 | (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))), | |
54a0048b SL |
530 | |
531 | (U8(a), U8(b)) => Ok(U8(a%b)), | |
532 | (U16(a), U16(b)) => Ok(U16(a%b)), | |
533 | (U32(a), U32(b)) => Ok(U32(a%b)), | |
534 | (U64(a), U64(b)) => Ok(U64(a%b)), | |
32a655c1 | 535 | (U128(a), U128(b)) => Ok(U128(a%b)), |
3157f602 | 536 | (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))), |
54a0048b SL |
537 | (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))), |
538 | (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))), | |
54a0048b SL |
539 | |
540 | _ => Err(UnequalTypes(Op::Rem)), | |
541 | } | |
542 | } | |
543 | } | |
544 | ||
545 | impl ::std::ops::Shl<ConstInt> for ConstInt { | |
546 | type Output = Result<Self, ConstMathErr>; | |
547 | fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
548 | let b = rhs.to_u32().ok_or(ShiftNegative)?; | |
549 | match self { | |
550 | I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
551 | I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
552 | I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
553 | I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
32a655c1 | 554 | I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))), |
3157f602 | 555 | Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))), |
54a0048b SL |
556 | Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))), |
557 | Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))), | |
558 | U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
559 | U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
560 | U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
561 | U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))), | |
32a655c1 | 562 | U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))), |
3157f602 | 563 | Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))), |
54a0048b SL |
564 | Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))), |
565 | Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))), | |
54a0048b SL |
566 | } |
567 | } | |
568 | } | |
569 | ||
570 | impl ::std::ops::Shr<ConstInt> for ConstInt { | |
571 | type Output = Result<Self, ConstMathErr>; | |
572 | fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> { | |
573 | let b = rhs.to_u32().ok_or(ShiftNegative)?; | |
574 | match self { | |
575 | I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
576 | I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
577 | I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
a7813a04 | 578 | I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))), |
32a655c1 | 579 | I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))), |
3157f602 | 580 | Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))), |
54a0048b SL |
581 | Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))), |
582 | Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))), | |
583 | U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
584 | U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
585 | U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
586 | U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))), | |
32a655c1 | 587 | U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))), |
3157f602 | 588 | Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))), |
54a0048b SL |
589 | Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))), |
590 | Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))), | |
54a0048b SL |
591 | } |
592 | } | |
593 | } | |
594 | ||
595 | impl ::std::ops::Neg for ConstInt { | |
596 | type Output = Result<Self, ConstMathErr>; | |
597 | fn neg(self) -> Result<Self, ConstMathErr> { | |
598 | match self { | |
599 | I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))), | |
600 | I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))), | |
601 | I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))), | |
602 | I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))), | |
32a655c1 | 603 | I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))), |
3157f602 | 604 | Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))), |
54a0048b SL |
605 | Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))), |
606 | Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))), | |
32a655c1 SL |
607 | a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) | |
608 | a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a), | |
609 | U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation), | |
54a0048b SL |
610 | } |
611 | } | |
612 | } | |
613 | ||
614 | impl ::std::ops::Not for ConstInt { | |
615 | type Output = Result<Self, ConstMathErr>; | |
616 | fn not(self) -> Result<Self, ConstMathErr> { | |
617 | match self { | |
618 | I8(a) => Ok(I8(!a)), | |
619 | I16(a) => Ok(I16(!a)), | |
620 | I32(a) => Ok(I32(!a)), | |
621 | I64(a) => Ok(I64(!a)), | |
32a655c1 | 622 | I128(a) => Ok(I128(!a)), |
3157f602 | 623 | Isize(Is16(a)) => Ok(Isize(Is16(!a))), |
54a0048b SL |
624 | Isize(Is32(a)) => Ok(Isize(Is32(!a))), |
625 | Isize(Is64(a)) => Ok(Isize(Is64(!a))), | |
626 | U8(a) => Ok(U8(!a)), | |
627 | U16(a) => Ok(U16(!a)), | |
628 | U32(a) => Ok(U32(!a)), | |
629 | U64(a) => Ok(U64(!a)), | |
32a655c1 | 630 | U128(a) => Ok(U128(!a)), |
3157f602 | 631 | Usize(Us16(a)) => Ok(Usize(Us16(!a))), |
54a0048b SL |
632 | Usize(Us32(a)) => Ok(Usize(Us32(!a))), |
633 | Usize(Us64(a)) => Ok(Usize(Us64(!a))), | |
54a0048b SL |
634 | } |
635 | } | |
636 | } |