1#[deprecated(since = "0.2.0", note = "please use `json::primitive!` instead")]
30#[macro_export]
31#[doc(hidden)]
32macro_rules! __json_value {
33 ($matcher:expr) => {
34 $crate::__json_primitive!($matcher)
35 };
36}
37
38#[macro_export]
57#[doc(hidden)]
58macro_rules! __json_primitive {
59 ($matcher:expr) => {
60 $crate::matchers::__internal_unstable_do_not_depend_on_these::JsonPrimitiveMatcher::new(
61 $matcher,
62 )
63 };
64}
65
66#[doc(hidden)]
67pub mod internal {
68 use crate::matchers::json_matcher::internal::{IntoJsonMatcher, JsonMatcher};
69 use googletest::description::Description;
70 use googletest::matcher::{Matcher, MatcherBase, MatcherResult};
71 use serde_json::Value;
72
73 #[doc(hidden)]
74 #[derive(MatcherBase)]
75 pub struct JsonPrimitiveMatcher<M, T> {
76 inner: M,
77 phantom: std::marker::PhantomData<T>,
78 }
79
80 impl<M, T> JsonPrimitiveMatcher<M, T> {
81 pub fn new(inner: M) -> Self {
82 Self {
83 inner,
84 phantom: std::marker::PhantomData,
85 }
86 }
87 }
88
89 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, String>
90 where
91 M: for<'a> Matcher<&'a str>,
92 {
93 fn matches(&self, actual: &Value) -> MatcherResult {
94 match actual {
95 Value::String(s) => self.inner.matches(s),
96 _ => MatcherResult::NoMatch,
97 }
98 }
99 fn describe(&self, r: MatcherResult) -> Description {
100 self.inner.describe(r)
101 }
102 fn explain_match(&self, actual: &Value) -> Description {
103 match actual {
104 Value::String(s) => self.inner.explain_match(s),
105 _ => Description::new().text("which is not a JSON string".to_string()),
106 }
107 }
108 }
109
110 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i64>
111 where
112 M: Matcher<i64>,
113 {
114 fn matches(&self, actual: &Value) -> MatcherResult {
115 match actual {
116 Value::Number(n) => n
117 .as_i64()
118 .map_or(MatcherResult::NoMatch, |i| self.inner.matches(i)),
119 _ => MatcherResult::NoMatch,
120 }
121 }
122 fn describe(&self, r: MatcherResult) -> Description {
123 self.inner.describe(r)
124 }
125 fn explain_match(&self, actual: &Value) -> Description {
126 match actual {
127 Value::Number(n) => match n.as_i64() {
128 Some(i) => self.inner.explain_match(i),
129 None => Description::new().text(format!("number out of i64 range: {n}")),
130 },
131 _ => Description::new().text("which is not a JSON number"),
132 }
133 }
134 }
135
136 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, f64>
137 where
138 M: Matcher<f64>,
139 {
140 fn matches(&self, actual: &Value) -> MatcherResult {
141 match actual {
142 Value::Number(n) => n
143 .as_f64()
144 .map_or(MatcherResult::NoMatch, |f| self.inner.matches(f)),
145 _ => MatcherResult::NoMatch,
146 }
147 }
148 fn describe(&self, r: MatcherResult) -> Description {
149 self.inner.describe(r)
150 }
151 fn explain_match(&self, actual: &Value) -> Description {
152 match actual {
153 Value::Number(n) => match n.as_f64() {
154 Some(f) => self.inner.explain_match(f),
155 None => Description::new().text(format!("number not convertible to f64: {n}")),
156 },
157 _ => Description::new().text("which is not a JSON number"),
158 }
159 }
160 }
161
162 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, bool>
163 where
164 M: Matcher<bool>,
165 {
166 fn matches(&self, actual: &Value) -> MatcherResult {
167 match actual {
168 Value::Bool(b) => self.inner.matches(*b),
169 _ => MatcherResult::NoMatch,
170 }
171 }
172 fn describe(&self, r: MatcherResult) -> Description {
173 self.inner.describe(r)
174 }
175 fn explain_match(&self, actual: &Value) -> Description {
176 match actual {
177 Value::Bool(b) => self.inner.explain_match(*b),
178 _ => Description::new().text("which is not a JSON boolean"),
179 }
180 }
181 }
182
183 impl<M, T> JsonMatcher for JsonPrimitiveMatcher<M, T> where
184 JsonPrimitiveMatcher<M, T>: for<'a> Matcher<&'a Value>
185 {
186 }
187
188 impl<M> IntoJsonMatcher<i64> for M
190 where
191 M: Matcher<i64> + 'static,
192 {
193 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
194 Box::new(JsonPrimitiveMatcher::<M, i64>::new(self))
195 }
196 }
197
198 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, u64>
199 where
200 M: Matcher<u64>,
201 {
202 fn matches(&self, actual: &Value) -> MatcherResult {
203 match actual {
204 Value::Number(n) => n
205 .as_u64()
206 .map_or(MatcherResult::NoMatch, |u| self.inner.matches(u)),
207 _ => MatcherResult::NoMatch,
208 }
209 }
210 fn describe(&self, r: MatcherResult) -> Description {
211 self.inner.describe(r)
212 }
213 fn explain_match(&self, actual: &Value) -> Description {
214 match actual {
215 Value::Number(n) => match n.as_u64() {
216 Some(u) => self.inner.explain_match(u),
217 None => Description::new().text(format!("number out of u64 range: {n}")),
218 },
219 _ => Description::new().text("which is not a JSON number"),
220 }
221 }
222 }
223
224 impl<M> IntoJsonMatcher<u64> for M
225 where
226 M: Matcher<u64> + 'static,
227 {
228 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
229 Box::new(JsonPrimitiveMatcher::<M, u64>::new(self))
230 }
231 }
232
233 impl<M> IntoJsonMatcher<f64> for M
234 where
235 M: Matcher<f64> + 'static,
236 {
237 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
238 Box::new(JsonPrimitiveMatcher::<M, f64>::new(self))
239 }
240 }
241
242 impl<M> IntoJsonMatcher<String> for M
243 where
244 M: for<'a> Matcher<&'a str> + 'static,
245 {
246 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
247 Box::new(JsonPrimitiveMatcher::<M, String>::new(self))
248 }
249 }
250
251 impl<M> IntoJsonMatcher<bool> for M
252 where
253 M: Matcher<bool> + 'static,
254 {
255 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
256 Box::new(JsonPrimitiveMatcher::<M, bool>::new(self))
257 }
258 }
259
260 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i32>
261 where
262 M: Matcher<i32>,
263 {
264 fn matches(&self, actual: &Value) -> MatcherResult {
265 match actual {
266 Value::Number(n) => match n.as_i64() {
267 Some(i) => match i32::try_from(i) {
268 Ok(i32_val) => self.inner.matches(i32_val),
269 Err(_) => MatcherResult::NoMatch,
270 },
271 None => MatcherResult::NoMatch,
272 },
273 _ => MatcherResult::NoMatch,
274 }
275 }
276 fn describe(&self, r: MatcherResult) -> Description {
277 self.inner.describe(r)
278 }
279 fn explain_match(&self, actual: &Value) -> Description {
280 match actual {
281 Value::Number(n) => match n.as_i64() {
282 Some(i) => match i32::try_from(i) {
283 Ok(i32_val) => self.inner.explain_match(i32_val),
284 Err(_) => Description::new().text(format!("number out of i32 range: {n}")),
285 },
286 None => Description::new().text(format!("number out of i64 range: {n}")),
287 },
288 _ => Description::new().text("which is not a JSON number"),
289 }
290 }
291 }
292
293 impl<M> IntoJsonMatcher<i32> for M
294 where
295 M: Matcher<i32> + 'static,
296 {
297 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
298 Box::new(JsonPrimitiveMatcher::<M, i32>::new(self))
299 }
300 }
301
302 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i8>
303 where
304 M: Matcher<i8>,
305 {
306 fn matches(&self, actual: &Value) -> MatcherResult {
307 match actual {
308 Value::Number(n) => match n.as_i64() {
309 Some(i) => match i8::try_from(i) {
310 Ok(i8_val) => self.inner.matches(i8_val),
311 Err(_) => MatcherResult::NoMatch,
312 },
313 None => MatcherResult::NoMatch,
314 },
315 _ => MatcherResult::NoMatch,
316 }
317 }
318 fn describe(&self, r: MatcherResult) -> Description {
319 self.inner.describe(r)
320 }
321 fn explain_match(&self, actual: &Value) -> Description {
322 match actual {
323 Value::Number(n) => match n.as_i64() {
324 Some(i) => match i8::try_from(i) {
325 Ok(i8_val) => self.inner.explain_match(i8_val),
326 Err(_) => Description::new().text(format!("number out of i8 range: {n}")),
327 },
328 None => Description::new().text(format!("number out of i64 range: {n}")),
329 },
330 _ => Description::new().text("which is not a JSON number"),
331 }
332 }
333 }
334
335 impl<M> IntoJsonMatcher<i8> for M
336 where
337 M: Matcher<i8> + 'static,
338 {
339 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
340 Box::new(JsonPrimitiveMatcher::<M, i8>::new(self))
341 }
342 }
343
344 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i16>
345 where
346 M: Matcher<i16>,
347 {
348 fn matches(&self, actual: &Value) -> MatcherResult {
349 match actual {
350 Value::Number(n) => match n.as_i64() {
351 Some(i) => match i16::try_from(i) {
352 Ok(i16_val) => self.inner.matches(i16_val),
353 Err(_) => MatcherResult::NoMatch,
354 },
355 None => MatcherResult::NoMatch,
356 },
357 _ => MatcherResult::NoMatch,
358 }
359 }
360 fn describe(&self, r: MatcherResult) -> Description {
361 self.inner.describe(r)
362 }
363 fn explain_match(&self, actual: &Value) -> Description {
364 match actual {
365 Value::Number(n) => match n.as_i64() {
366 Some(i) => match i16::try_from(i) {
367 Ok(i16_val) => self.inner.explain_match(i16_val),
368 Err(_) => Description::new().text(format!("number out of i16 range: {n}")),
369 },
370 None => Description::new().text(format!("number out of i64 range: {n}")),
371 },
372 _ => Description::new().text("which is not a JSON number"),
373 }
374 }
375 }
376
377 impl<M> IntoJsonMatcher<i16> for M
378 where
379 M: Matcher<i16> + 'static,
380 {
381 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
382 Box::new(JsonPrimitiveMatcher::<M, i16>::new(self))
383 }
384 }
385
386 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, u8>
387 where
388 M: Matcher<u8>,
389 {
390 fn matches(&self, actual: &Value) -> MatcherResult {
391 match actual {
392 Value::Number(n) => match n.as_u64() {
393 Some(u) => match u8::try_from(u) {
394 Ok(u8_val) => self.inner.matches(u8_val),
395 Err(_) => MatcherResult::NoMatch,
396 },
397 None => MatcherResult::NoMatch,
398 },
399 _ => MatcherResult::NoMatch,
400 }
401 }
402 fn describe(&self, r: MatcherResult) -> Description {
403 self.inner.describe(r)
404 }
405 fn explain_match(&self, actual: &Value) -> Description {
406 match actual {
407 Value::Number(n) => match n.as_u64() {
408 Some(u) => match u8::try_from(u) {
409 Ok(u8_val) => self.inner.explain_match(u8_val),
410 Err(_) => Description::new().text(format!("number out of u8 range: {n}")),
411 },
412 None => Description::new().text(format!("number out of u64 range: {n}")),
413 },
414 _ => Description::new().text("which is not a JSON number"),
415 }
416 }
417 }
418
419 impl<M> IntoJsonMatcher<u8> for M
420 where
421 M: Matcher<u8> + 'static,
422 {
423 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
424 Box::new(JsonPrimitiveMatcher::<M, u8>::new(self))
425 }
426 }
427
428 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, u16>
429 where
430 M: Matcher<u16>,
431 {
432 fn matches(&self, actual: &Value) -> MatcherResult {
433 match actual {
434 Value::Number(n) => match n.as_u64() {
435 Some(u) => match u16::try_from(u) {
436 Ok(u16_val) => self.inner.matches(u16_val),
437 Err(_) => MatcherResult::NoMatch,
438 },
439 None => MatcherResult::NoMatch,
440 },
441 _ => MatcherResult::NoMatch,
442 }
443 }
444 fn describe(&self, r: MatcherResult) -> Description {
445 self.inner.describe(r)
446 }
447 fn explain_match(&self, actual: &Value) -> Description {
448 match actual {
449 Value::Number(n) => match n.as_u64() {
450 Some(u) => match u16::try_from(u) {
451 Ok(u16_val) => self.inner.explain_match(u16_val),
452 Err(_) => Description::new().text(format!("number out of u16 range: {n}")),
453 },
454 None => Description::new().text(format!("number out of u64 range: {n}")),
455 },
456 _ => Description::new().text("which is not a JSON number"),
457 }
458 }
459 }
460
461 impl<M> IntoJsonMatcher<u16> for M
462 where
463 M: Matcher<u16> + 'static,
464 {
465 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
466 Box::new(JsonPrimitiveMatcher::<M, u16>::new(self))
467 }
468 }
469
470 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, u32>
471 where
472 M: Matcher<u32>,
473 {
474 fn matches(&self, actual: &Value) -> MatcherResult {
475 match actual {
476 Value::Number(n) => match n.as_u64() {
477 Some(u) => match u32::try_from(u) {
478 Ok(u32_val) => self.inner.matches(u32_val),
479 Err(_) => MatcherResult::NoMatch,
480 },
481 None => MatcherResult::NoMatch,
482 },
483 _ => MatcherResult::NoMatch,
484 }
485 }
486 fn describe(&self, r: MatcherResult) -> Description {
487 self.inner.describe(r)
488 }
489 fn explain_match(&self, actual: &Value) -> Description {
490 match actual {
491 Value::Number(n) => match n.as_u64() {
492 Some(u) => match u32::try_from(u) {
493 Ok(u32_val) => self.inner.explain_match(u32_val),
494 Err(_) => Description::new().text(format!("number out of u32 range: {n}")),
495 },
496 None => Description::new().text(format!("number out of u64 range: {n}")),
497 },
498 _ => Description::new().text("which is not a JSON number"),
499 }
500 }
501 }
502
503 impl<M> IntoJsonMatcher<u32> for M
504 where
505 M: Matcher<u32> + 'static,
506 {
507 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
508 Box::new(JsonPrimitiveMatcher::<M, u32>::new(self))
509 }
510 }
511
512 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, usize>
514 where
515 M: Matcher<usize>,
516 {
517 fn matches(&self, actual: &Value) -> MatcherResult {
518 match actual {
519 Value::Number(n) => match n.as_u64() {
520 Some(u) => match usize::try_from(u) {
521 Ok(usize_val) => self.inner.matches(usize_val),
522 Err(_) => MatcherResult::NoMatch,
523 },
524 None => MatcherResult::NoMatch,
525 },
526 _ => MatcherResult::NoMatch,
527 }
528 }
529
530 fn describe(&self, r: MatcherResult) -> Description {
531 self.inner.describe(r)
532 }
533
534 fn explain_match(&self, actual: &Value) -> Description {
535 match actual {
536 Value::Number(n) => match n.as_u64() {
537 Some(u) => match usize::try_from(u) {
538 Ok(usize_val) => self.inner.explain_match(usize_val),
539 Err(_) => {
540 Description::new().text(format!("number out of usize range: {n}"))
541 }
542 },
543 None => Description::new().text(format!("number not convertible to u64: {n}")),
544 },
545 _ => Description::new().text("which is not a JSON number"),
546 }
547 }
548 }
549
550 impl<M> IntoJsonMatcher<usize> for M
551 where
552 M: Matcher<usize> + 'static,
553 {
554 fn into_json_matcher(self) -> Box<dyn JsonMatcher> {
555 Box::new(JsonPrimitiveMatcher::<M, usize>::new(self))
556 }
557 }
558}