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