summaryrefslogtreecommitdiff
path: root/src/eval/int.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval/int.rs')
-rw-r--r--src/eval/int.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/eval/int.rs b/src/eval/int.rs
new file mode 100644
index 00000000..4e081617
--- /dev/null
+++ b/src/eval/int.rs
@@ -0,0 +1,81 @@
+use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize};
+
+use super::{cast, Value};
+
+macro_rules! signed_int {
+ ($($ty:ty)*) => {
+ $(cast! {
+ $ty,
+ self => Value::Int(self as i64),
+ v: i64 => v.try_into().map_err(|_| "number too large")?,
+ })*
+ }
+}
+
+macro_rules! unsigned_int {
+ ($($ty:ty)*) => {
+ $(cast! {
+ $ty,
+ self => Value::Int(self as i64),
+ v: i64 => v.try_into().map_err(|_| {
+ if v < 0 {
+ "number must be at least zero"
+ } else {
+ "number too large"
+ }
+ })?,
+ })*
+ }
+}
+
+macro_rules! signed_nonzero {
+ ($($ty:ty)*) => {
+ $(cast! {
+ $ty,
+ self => Value::Int(self.get() as i64),
+ v: i64 => v
+ .try_into()
+ .ok()
+ .and_then($ty::new)
+ .ok_or_else(|| if v == 0 {
+ "number must not be zero"
+ } else {
+ "number too large"
+ })?,
+ })*
+ }
+}
+
+macro_rules! unsigned_nonzero {
+ ($($ty:ty)*) => {
+ $(cast! {
+ $ty,
+ self => Value::Int(self.get() as i64),
+ v: i64 => v
+ .try_into()
+ .ok()
+ .and_then($ty::new)
+ .ok_or_else(|| if v <= 0 {
+ "number must be positive"
+ } else {
+ "number too large"
+ })?,
+ })*
+ }
+}
+
+signed_int! {
+ i8 i16 i32 isize
+}
+
+unsigned_int! {
+ u8 u16 u32 u64 usize
+}
+
+signed_nonzero! {
+ NonZeroI64 NonZeroIsize
+}
+
+unsigned_nonzero! {
+ NonZeroU64 NonZeroUsize
+}