diesel/pg/types/floats/
quickcheck_impls.rs

1#![allow(clippy::cast_sign_loss)] // test code
2
3use quickcheck::{Arbitrary, Gen};
4
5use super::PgNumeric;
6
7const SCALE_MASK: u16 = 0x3FFF;
8
9impl Arbitrary for PgNumeric {
10    fn arbitrary(g: &mut Gen) -> Self {
11        let mut variant = Option::<bool>::arbitrary(g);
12        let mut weight = -1;
13        while weight < 0 {
14            // Oh postgres... Don't ever change. https://bit.ly/lol-code-comments
15            weight = i16::arbitrary(g);
16        }
17        let scale = u16::arbitrary(g) & SCALE_MASK;
18        let digits = gen_vec_of_appropriate_length_valid_digits(g, weight as u16, scale);
19        if digits.is_empty() {
20            weight = 0;
21            variant = Some(true);
22        }
23
24        match variant {
25            Some(true) => PgNumeric::Positive {
26                digits: digits,
27                weight: weight,
28                scale: scale,
29            },
30            Some(false) => PgNumeric::Negative {
31                digits: digits,
32                weight: weight,
33                scale: scale,
34            },
35            None => PgNumeric::NaN,
36        }
37    }
38}
39
40fn gen_vec_of_appropriate_length_valid_digits(g: &mut Gen, weight: u16, scale: u16) -> Vec<i16> {
41    let max_digits = ::std::cmp::min(weight, scale);
42    let mut digits = Vec::<Digit>::arbitrary(g)
43        .into_iter()
44        .map(|d| d.0)
45        .skip_while(|d| d == &0) // drop leading zeros
46        .take(max_digits as usize)
47        .collect::<Vec<_>>();
48    while digits.last() == Some(&0) {
49        digits.pop(); // drop trailing zeros
50    }
51    digits
52}
53
54#[derive(Debug, Clone, Copy)]
55struct Digit(i16);
56
57impl Arbitrary for Digit {
58    fn arbitrary(g: &mut Gen) -> Self {
59        let mut n = -1;
60        while !(0..10_000).contains(&n) {
61            n = i16::arbitrary(g);
62        }
63        Digit(n)
64    }
65}