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