1use alloc::boxed::Box;
38
39use quickcheck::{empty_shrinker, single_shrinker, Arbitrary, Gen};
40
41use crate::{
42 Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
43};
44
45macro_rules! arbitrary_between {
47 ($type:ty; $gen:expr, $min:expr, $max:expr) => {{
48 let min = $min;
49 let max = $max;
50 let range = max - min;
51 <$type>::arbitrary($gen).rem_euclid(range + 1) + min
52 }};
53}
54
55impl Arbitrary for Date {
56 fn arbitrary(g: &mut Gen) -> Self {
57 unsafe {
59 Self::from_julian_day_unchecked(arbitrary_between!(
60 i32;
61 g,
62 Self::MIN.to_julian_day(),
63 Self::MAX.to_julian_day()
64 ))
65 }
66 }
67
68 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
69 Box::new(
70 self.to_ordinal_date()
71 .shrink()
72 .flat_map(|(year, ordinal)| Self::from_ordinal_date(year, ordinal)),
73 )
74 }
75}
76
77impl Arbitrary for Duration {
78 fn arbitrary(g: &mut Gen) -> Self {
79 Self::new_ranged(<_>::arbitrary(g), <_>::arbitrary(g))
80 }
81
82 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
83 Box::new(
84 (self.subsec_nanoseconds_ranged(), self.whole_seconds())
85 .shrink()
86 .map(|(mut nanoseconds, seconds)| {
87 if (seconds > 0 && nanoseconds.get() < 0)
89 || (seconds < 0 && nanoseconds.get() > 0)
90 {
91 nanoseconds = nanoseconds.neg();
92 }
93
94 Self::new_ranged_unchecked(seconds, nanoseconds)
95 }),
96 )
97 }
98}
99
100impl Arbitrary for Time {
101 fn arbitrary(g: &mut Gen) -> Self {
102 Self::from_hms_nanos_ranged(
103 <_>::arbitrary(g),
104 <_>::arbitrary(g),
105 <_>::arbitrary(g),
106 <_>::arbitrary(g),
107 )
108 }
109
110 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
111 Box::new(
112 self.as_hms_nano_ranged()
113 .shrink()
114 .map(|(hour, minute, second, nanosecond)| {
115 Self::from_hms_nanos_ranged(hour, minute, second, nanosecond)
116 }),
117 )
118 }
119}
120
121impl Arbitrary for PrimitiveDateTime {
122 fn arbitrary(g: &mut Gen) -> Self {
123 Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
124 }
125
126 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
127 Box::new(
128 (self.date(), self.time())
129 .shrink()
130 .map(|(date, time)| Self::new(date, time)),
131 )
132 }
133}
134
135impl Arbitrary for UtcOffset {
136 fn arbitrary(g: &mut Gen) -> Self {
137 Self::from_hms_ranged(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
138 }
139
140 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
141 Box::new(
142 self.as_hms_ranged()
143 .shrink()
144 .map(|(hours, minutes, seconds)| Self::from_hms_ranged(hours, minutes, seconds)),
145 )
146 }
147}
148
149impl Arbitrary for OffsetDateTime {
150 fn arbitrary(g: &mut Gen) -> Self {
151 Self::new_in_offset(<_>::arbitrary(g), <_>::arbitrary(g), <_>::arbitrary(g))
152 }
153
154 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
155 Box::new(
156 (self.date(), self.time(), self.offset())
157 .shrink()
158 .map(|(date, time, offset)| Self::new_in_offset(date, time, offset)),
159 )
160 }
161}
162
163impl Arbitrary for UtcDateTime {
164 fn arbitrary(g: &mut Gen) -> Self {
165 Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
166 }
167
168 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
169 Box::new(
170 (self.date(), self.time())
171 .shrink()
172 .map(|(date, time)| Self::new(date, time)),
173 )
174 }
175}
176
177impl Arbitrary for Weekday {
178 fn arbitrary(g: &mut Gen) -> Self {
179 use Weekday::*;
180 match arbitrary_between!(u8; g, 0, 6) {
181 0 => Monday,
182 1 => Tuesday,
183 2 => Wednesday,
184 3 => Thursday,
185 4 => Friday,
186 5 => Saturday,
187 val => {
188 debug_assert!(val == 6);
189 Sunday
190 }
191 }
192 }
193
194 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
195 match self {
196 Self::Monday => empty_shrinker(),
197 _ => single_shrinker(self.previous()),
198 }
199 }
200}
201
202impl Arbitrary for Month {
203 fn arbitrary(g: &mut Gen) -> Self {
204 use Month::*;
205 match arbitrary_between!(u8; g, 1, 12) {
206 1 => January,
207 2 => February,
208 3 => March,
209 4 => April,
210 5 => May,
211 6 => June,
212 7 => July,
213 8 => August,
214 9 => September,
215 10 => October,
216 11 => November,
217 val => {
218 debug_assert!(val == 12);
219 December
220 }
221 }
222 }
223
224 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
225 match self {
226 Self::January => empty_shrinker(),
227 _ => single_shrinker(self.previous()),
228 }
229 }
230}