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
151macro_rules! impl_float {
152 (
153 $(
154 $variant:ident($ty:ty) {
155 $to:ident
156 $to_unwrap:ident
157 $is:ident
158 $unwrap_msg:literal
159 }
160 )*
161 ) => {
162 impl Type {
163 $(
164 pub fn $is(&self) -> bool {
166 matches!(self, Self::$variant)
167 }
168 )*
169 }
170
171 $(
172 impl From<$ty> for Value {
173 fn from(value: $ty) -> Self {
174 Self::$variant(value)
175 }
176 }
177
178 impl From<&$ty> for Value {
179 fn from(value: &$ty) -> Self {
180 Self::$variant(*value)
181 }
182 }
183
184 impl Value {
185 #[track_caller]
192 pub fn $to_unwrap(&self) -> $ty {
193 self.$to().expect($unwrap_msg)
194 }
195 }
196
197 impl TryFrom<Value> for $ty {
198 type Error = crate::Error;
199
200 fn try_from(value: Value) -> crate::Result<Self> {
201 value.$to().ok_or_else(|| {
202 crate::Error::type_conversion(value.clone(), stringify!($ty))
203 })
204 }
205 }
206 )*
207 };
208}
209
210impl_float! {
211 F32(f32) {
212 to_f32
213 to_f32_unwrap
214 is_f32
215 "value is not a finite f32"
216 }
217 F64(f64) {
218 to_f64
219 to_f64_unwrap
220 is_f64
221 "value is not a float type"
222 }
223}
224
225impl Value {
226 pub fn to_f32(&self) -> Option<f32> {
231 match self {
232 Value::F32(v) => Some(*v),
233 Value::F64(v) => {
234 let converted = *v as f32;
235 if converted.is_infinite() && !v.is_infinite() {
236 None
237 } else {
238 Some(converted)
239 }
240 }
241 _ => None,
242 }
243 }
244
245 pub fn to_f64(&self) -> Option<f64> {
250 match self {
251 Value::F32(v) => Some(*v as f64),
252 Value::F64(v) => Some(*v),
253 _ => None,
254 }
255 }
256}
257
258impl_num! {
259 I8(i8) {
260 to_i8
261 to_i8_unwrap
262 is_i8
263 }
264 I16(i16) {
265 to_i16
266 to_i16_unwrap
267 is_i16
268 }
269 I32(i32) {
270 to_i32
271 to_i32_unwrap
272 is_i32
273 }
274 I64(i64) {
275 to_i64
276 to_i64_unwrap
277 is_i64
278 }
279 U8(u8) {
280 to_u8
281 to_u8_unwrap
282 is_u8
283 }
284 U16(u16) {
285 to_u16
286 to_u16_unwrap
287 is_u16
288 }
289 U32(u32) {
290 to_u32
291 to_u32_unwrap
292 is_u32
293 }
294 U64(u64) {
295 to_u64
296 to_u64_unwrap
297 is_u64
298 }
299}
300
301impl From<usize> for Value {
302 fn from(value: usize) -> Self {
303 Value::U64(value as u64)
304 }
305}
306
307impl From<&usize> for Value {
308 fn from(value: &usize) -> Self {
309 Value::U64(*value as u64)
310 }
311}
312
313impl From<isize> for Value {
314 fn from(value: isize) -> Self {
315 Value::I64(value as i64)
316 }
317}
318
319impl From<&isize> for Value {
320 fn from(value: &isize) -> Self {
321 Value::I64(*value as i64)
322 }
323}
324
325#[cfg(feature = "assert-struct")]
326impl assert_struct::Like<usize> for Value {
327 fn like(&self, pattern: &usize) -> bool {
328 usize::try_from(self)
329 .map(|v| v == *pattern)
330 .unwrap_or(false)
331 }
332}
333
334#[cfg(feature = "assert-struct")]
335impl assert_struct::Like<usize> for Expr {
336 fn like(&self, pattern: &usize) -> bool {
337 match self {
338 Expr::Value(v) => v.like(pattern),
339 _ => false,
340 }
341 }
342}
343
344#[cfg(feature = "assert-struct")]
345impl assert_struct::Like<isize> for Value {
346 fn like(&self, pattern: &isize) -> bool {
347 isize::try_from(self)
348 .map(|v| v == *pattern)
349 .unwrap_or(false)
350 }
351}
352
353#[cfg(feature = "assert-struct")]
354impl assert_struct::Like<isize> for Expr {
355 fn like(&self, pattern: &isize) -> bool {
356 match self {
357 Expr::Value(v) => v.like(pattern),
358 _ => false,
359 }
360 }
361}
362
363impl TryFrom<Value> for usize {
365 type Error = crate::Error;
366
367 fn try_from(value: Value) -> crate::Result<Self> {
368 (&value).try_into()
369 }
370}
371
372impl TryFrom<&Value> for usize {
373 type Error = crate::Error;
374
375 fn try_from(value: &Value) -> crate::Result<Self> {
376 let u64_val = value
377 .to_u64()
378 .ok_or_else(|| crate::Error::type_conversion(value.clone(), "usize"))?;
379 u64_val
380 .try_into()
381 .map_err(|_| crate::Error::type_conversion(Value::U64(u64_val), "usize"))
382 }
383}
384
385impl TryFrom<Value> for isize {
386 type Error = crate::Error;
387
388 fn try_from(value: Value) -> crate::Result<Self> {
389 (&value).try_into()
390 }
391}
392
393impl TryFrom<&Value> for isize {
394 type Error = crate::Error;
395
396 fn try_from(value: &Value) -> crate::Result<Self> {
397 let i64_val = value
398 .to_i64()
399 .ok_or_else(|| crate::Error::type_conversion(value.clone(), "isize"))?;
400 i64_val
401 .try_into()
402 .map_err(|_| crate::Error::type_conversion(Value::I64(i64_val), "isize"))
403 }
404}