toasty_core/stmt/
num.rs

1use super::{Expr, Type, Value};
2
3macro_rules! try_from {
4    ($v:expr, $ty:ty) => {
5        match $v {
6            Value::I8(v) => <$ty>::try_from(v).ok(),
7            Value::I16(v) => <$ty>::try_from(v).ok(),
8            Value::I32(v) => <$ty>::try_from(v).ok(),
9            Value::I64(v) => <$ty>::try_from(v).ok(),
10            Value::U8(v) => <$ty>::try_from(v).ok(),
11            Value::U16(v) => <$ty>::try_from(v).ok(),
12            Value::U32(v) => <$ty>::try_from(v).ok(),
13            Value::U64(v) => <$ty>::try_from(v).ok(),
14            _ => None,
15        }
16    };
17}
18
19macro_rules! impl_num {
20    (
21        $(
22            $variant:ident($ty:ty) {
23                $to:ident
24                $to_unwrap:ident
25                $is:ident
26            } )*
27    ) => {
28        impl Type {
29            $(
30                pub fn $is(&self) -> bool {
31                    matches!(self, Self::$variant)
32                }
33            )*
34        }
35
36        impl Value {
37            $(
38                pub fn $to(&self) -> Option<$ty> {
39                    try_from!(*self, $ty)
40                }
41
42                #[track_caller]
43                pub fn $to_unwrap(&self) -> $ty {
44                    try_from!(*self, $ty).expect("out of range integral type conversion attempted")
45                }
46            )*
47        }
48
49        $(
50            impl PartialEq<$ty> for Value {
51                fn eq(&self, other: &$ty) -> bool {
52                    try_from!(*self, $ty).map(|v| v == *other).unwrap_or(false)
53                }
54            }
55
56            impl PartialEq<Value> for $ty {
57                fn eq(&self, other: &Value) -> bool {
58                    other.eq(self)
59                }
60            }
61
62            impl PartialEq<$ty> for Expr {
63                fn eq(&self, other: &$ty) -> bool {
64                    match self {
65                        Expr::Value(value) => value.eq(other),
66                        _ => false,
67                    }
68                }
69            }
70
71            impl PartialEq<Expr> for $ty {
72                fn eq(&self, other: &Expr) -> bool {
73                    other.eq(self)
74                }
75            }
76
77            impl From<$ty> for Value {
78                fn from(value: $ty) -> Self {
79                    Self::$variant(value)
80                }
81            }
82
83            impl From<&$ty> for Value {
84                fn from(value: &$ty) -> Self {
85                    Self::$variant(*value)
86                }
87            }
88
89            impl TryFrom<Value> for $ty {
90                type Error = crate::Error;
91
92                fn try_from(value: Value) -> crate::Result<Self> {
93                    value.$to().ok_or_else(|| {
94                        crate::Error::type_conversion(value.clone(), stringify!($ty))
95                    })
96                }
97            }
98
99            #[cfg(feature = "assert-struct")]
100            impl assert_struct::Like<$ty> for Value {
101                fn like(&self, pattern: &$ty) -> bool {
102                    try_from!(*self, $ty).map(|v| v == *pattern).unwrap_or(false)
103                }
104            }
105
106            #[cfg(feature = "assert-struct")]
107            impl assert_struct::Like<$ty> for Expr {
108                fn like(&self, pattern: &$ty) -> bool {
109                    match self {
110                        Expr::Value(value) => value.like(pattern),
111                        _ => false,
112                    }
113                }
114            }
115        )*
116    };
117}
118
119impl_num! {
120    I8(i8) {
121        to_i8
122        to_i8_unwrap
123        is_i8
124    }
125    I16(i16) {
126        to_i16
127        to_i16_unwrap
128        is_i16
129    }
130    I32(i32) {
131        to_i32
132        to_i32_unwrap
133        is_i32
134    }
135    I64(i64) {
136        to_i64
137        to_i64_unwrap
138        is_i64
139    }
140    U8(u8) {
141        to_u8
142        to_u8_unwrap
143        is_u8
144    }
145    U16(u16) {
146        to_u16
147        to_u16_unwrap
148        is_u16
149    }
150    U32(u32) {
151        to_u32
152        to_u32_unwrap
153        is_u32
154    }
155    U64(u64) {
156        to_u64
157        to_u64_unwrap
158        is_u64
159    }
160}
161
162impl From<usize> for Value {
163    fn from(value: usize) -> Self {
164        Value::U64(value as u64)
165    }
166}
167
168impl From<&usize> for Value {
169    fn from(value: &usize) -> Self {
170        Value::U64(*value as u64)
171    }
172}
173
174impl From<isize> for Value {
175    fn from(value: isize) -> Self {
176        Value::I64(value as i64)
177    }
178}
179
180impl From<&isize> for Value {
181    fn from(value: &isize) -> Self {
182        Value::I64(*value as i64)
183    }
184}
185
186#[cfg(feature = "assert-struct")]
187impl assert_struct::Like<usize> for Value {
188    fn like(&self, pattern: &usize) -> bool {
189        usize::try_from(self)
190            .map(|v| v == *pattern)
191            .unwrap_or(false)
192    }
193}
194
195#[cfg(feature = "assert-struct")]
196impl assert_struct::Like<usize> for Expr {
197    fn like(&self, pattern: &usize) -> bool {
198        match self {
199            Expr::Value(v) => v.like(pattern),
200            _ => false,
201        }
202    }
203}
204
205#[cfg(feature = "assert-struct")]
206impl assert_struct::Like<isize> for Value {
207    fn like(&self, pattern: &isize) -> bool {
208        isize::try_from(self)
209            .map(|v| v == *pattern)
210            .unwrap_or(false)
211    }
212}
213
214#[cfg(feature = "assert-struct")]
215impl assert_struct::Like<isize> for Expr {
216    fn like(&self, pattern: &isize) -> bool {
217        match self {
218            Expr::Value(v) => v.like(pattern),
219            _ => false,
220        }
221    }
222}
223
224// Pointer-sized integers convert from their fixed-size equivalents
225impl TryFrom<Value> for usize {
226    type Error = crate::Error;
227
228    fn try_from(value: Value) -> crate::Result<Self> {
229        (&value).try_into()
230    }
231}
232
233impl TryFrom<&Value> for usize {
234    type Error = crate::Error;
235
236    fn try_from(value: &Value) -> crate::Result<Self> {
237        let u64_val = value
238            .to_u64()
239            .ok_or_else(|| crate::Error::type_conversion(value.clone(), "usize"))?;
240        u64_val
241            .try_into()
242            .map_err(|_| crate::Error::type_conversion(Value::U64(u64_val), "usize"))
243    }
244}
245
246impl TryFrom<Value> for isize {
247    type Error = crate::Error;
248
249    fn try_from(value: Value) -> crate::Result<Self> {
250        (&value).try_into()
251    }
252}
253
254impl TryFrom<&Value> for isize {
255    type Error = crate::Error;
256
257    fn try_from(value: &Value) -> crate::Result<Self> {
258        let i64_val = value
259            .to_i64()
260            .ok_or_else(|| crate::Error::type_conversion(value.clone(), "isize"))?;
261        i64_val
262            .try_into()
263            .map_err(|_| crate::Error::type_conversion(Value::I64(i64_val), "isize"))
264    }
265}