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
224impl 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}