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