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