1use core::ops::{Div, Rem};
7
8c0nst::c0nst! {
9pub c0nst trait Euclid: Sized + [c0nst] Div<Self> + [c0nst] Rem<Self> {
10 fn div_euclid(self, v: Self) -> <Self as Div<Self>>::Output;
30
31 fn rem_euclid(self, v: Self) -> <Self as Rem<Self>>::Output;
55
56 fn div_rem_euclid(self, v: Self) -> (<Self as Div<Self>>::Output, <Self as Rem<Self>>::Output);
74}
75}
76
77macro_rules! euclid_forward_impl {
78 ($($t:ty)*) => {$(
79 c0nst::c0nst! {
80 c0nst impl Euclid for $t {
81 #[inline]
82 fn div_euclid(self, v: $t) -> Self {
83 <$t>::div_euclid(self, v)
84 }
85
86 #[inline]
87 fn rem_euclid(self, v: $t) -> Self {
88 <$t>::rem_euclid(self, v)
89 }
90
91 #[inline]
92 fn div_rem_euclid(self, v: $t) -> ($t, $t) {
93 (<$t>::div_euclid(self, v), <$t>::rem_euclid(self, v))
94 }
95 }
96 }
97 )*}
98}
99
100euclid_forward_impl!(isize i8 i16 i32 i64 i128);
101euclid_forward_impl!(usize u8 u16 u32 u64 u128);
102
103#[cfg(feature = "std")]
106macro_rules! euclid_forward_impl_float {
107 ($($t:ty)*) => {$(
108 impl Euclid for $t {
109 #[inline]
110 fn div_euclid(self, v: $t) -> Self {
111 <$t>::div_euclid(self, v)
112 }
113
114 #[inline]
115 fn rem_euclid(self, v: $t) -> Self {
116 <$t>::rem_euclid(self, v)
117 }
118
119 #[inline]
120 fn div_rem_euclid(self, v: $t) -> ($t, $t) {
121 (<$t>::div_euclid(self, v), <$t>::rem_euclid(self, v))
122 }
123 }
124 )*}
125}
126
127#[cfg(feature = "std")]
128euclid_forward_impl_float!(f32 f64);
129
130#[cfg(not(feature = "std"))]
131impl Euclid for f32 {
132 #[inline]
133 fn div_euclid(self, v: f32) -> f32 {
134 let q = <f32 as crate::float::FloatCore>::trunc(self / v);
135 if self % v < 0.0 {
136 return if v > 0.0 { q - 1.0 } else { q + 1.0 };
137 }
138 q
139 }
140
141 #[inline]
142 fn rem_euclid(self, v: f32) -> f32 {
143 let r = self % v;
144 if r < 0.0 {
145 r + <f32 as crate::float::FloatCore>::abs(v)
146 } else {
147 r
148 }
149 }
150
151 #[inline]
152 fn div_rem_euclid(self, v: f32) -> (f32, f32) {
153 (Euclid::div_euclid(self, v), Euclid::rem_euclid(self, v))
154 }
155}
156
157#[cfg(not(feature = "std"))]
158impl Euclid for f64 {
159 #[inline]
160 fn div_euclid(self, v: f64) -> f64 {
161 let q = <f64 as crate::float::FloatCore>::trunc(self / v);
162 if self % v < 0.0 {
163 return if v > 0.0 { q - 1.0 } else { q + 1.0 };
164 }
165 q
166 }
167
168 #[inline]
169 fn rem_euclid(self, v: f64) -> f64 {
170 let r = self % v;
171 if r < 0.0 {
172 r + <f64 as crate::float::FloatCore>::abs(v)
173 } else {
174 r
175 }
176 }
177
178 #[inline]
179 fn div_rem_euclid(self, v: f64) -> (f64, f64) {
180 (Euclid::div_euclid(self, v), Euclid::rem_euclid(self, v))
181 }
182}
183
184c0nst::c0nst! {
185pub c0nst trait CheckedEuclid: [c0nst] Euclid {
186 fn checked_div_euclid(self, v: Self) -> Option<<Self as Div<Self>>::Output>;
189
190 fn checked_rem_euclid(self, v: Self) -> Option<<Self as Rem<Self>>::Output>;
193
194 fn checked_div_rem_euclid(self, v: Self) -> Option<(<Self as Div<Self>>::Output, <Self as Rem<Self>>::Output)>;
210}
211}
212
213macro_rules! checked_euclid_forward_impl {
214 ($($t:ty)*) => {$(
215 c0nst::c0nst! {
216 c0nst impl CheckedEuclid for $t {
217 #[inline]
218 fn checked_div_euclid(self, v: $t) -> Option<Self> {
219 <$t>::checked_div_euclid(self, v)
220 }
221
222 #[inline]
223 fn checked_rem_euclid(self, v: $t) -> Option<Self> {
224 <$t>::checked_rem_euclid(self, v)
225 }
226
227 #[inline]
230 fn checked_div_rem_euclid(self, v: $t) -> Option<(Self, Self)> {
231 let d = match <$t>::checked_div_euclid(self, v) {
232 Some(x) => x,
233 None => return None,
234 };
235 let r = match <$t>::checked_rem_euclid(self, v) {
236 Some(x) => x,
237 None => return None,
238 };
239 Some((d, r))
240 }
241 }
242 }
243 )*}
244}
245
246checked_euclid_forward_impl!(isize i8 i16 i32 i64 i128);
247checked_euclid_forward_impl!(usize u8 u16 u32 u64 u128);
248
249c0nst::c0nst! {
250pub c0nst trait WrappingEuclid: [c0nst] Euclid {
252 fn wrapping_div_euclid(self, v: Self) -> <Self as Div<Self>>::Output;
260
261 fn wrapping_rem_euclid(self, v: Self) -> <Self as Rem<Self>>::Output;
269}
270}
271
272macro_rules! wrapping_euclid_forward_impl {
273 ($($t:ty)*) => {$(
274 c0nst::c0nst! {
275 c0nst impl WrappingEuclid for $t {
276 #[inline]
277 fn wrapping_div_euclid(self, v: $t) -> Self {
278 <$t>::wrapping_div_euclid(self, v)
279 }
280
281 #[inline]
282 fn wrapping_rem_euclid(self, v: $t) -> Self {
283 <$t>::wrapping_rem_euclid(self, v)
284 }
285 }
286 }
287 )*}
288}
289
290wrapping_euclid_forward_impl!(isize i8 i16 i32 i64 i128);
291wrapping_euclid_forward_impl!(usize u8 u16 u32 u64 u128);
292
293c0nst::c0nst! {
294pub c0nst trait OverflowingEuclid: [c0nst] Euclid {
296 fn overflowing_div_euclid(self, v: Self) -> (<Self as Div<Self>>::Output, bool);
304
305 fn overflowing_rem_euclid(self, v: Self) -> (<Self as Rem<Self>>::Output, bool);
314}
315}
316
317macro_rules! overflowing_euclid_forward_impl {
318 ($($t:ty)*) => {$(
319 c0nst::c0nst! {
320 c0nst impl OverflowingEuclid for $t {
321 #[inline]
322 fn overflowing_div_euclid(self, v: $t) -> (Self, bool) {
323 <$t>::overflowing_div_euclid(self, v)
324 }
325
326 #[inline]
327 fn overflowing_rem_euclid(self, v: $t) -> (Self, bool) {
328 <$t>::overflowing_rem_euclid(self, v)
329 }
330 }
331 }
332 )*}
333}
334
335overflowing_euclid_forward_impl!(isize i8 i16 i32 i64 i128);
336overflowing_euclid_forward_impl!(usize u8 u16 u32 u64 u128);
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341
342 #[test]
343 fn euclid_unsigned() {
344 macro_rules! test_euclid {
345 ($($t:ident)+) => {
346 $(
347 {
348 let x: $t = 10;
349 let y: $t = 3;
350 let div = Euclid::div_euclid(x, y);
351 let rem = Euclid::rem_euclid(x, y);
352 assert_eq!(div, 3);
353 assert_eq!(rem, 1);
354 assert_eq!((div, rem), Euclid::div_rem_euclid(x, y));
355 }
356 )+
357 };
358 }
359
360 test_euclid!(usize u8 u16 u32 u64);
361 }
362
363 #[test]
364 fn euclid_signed() {
365 macro_rules! test_euclid {
366 ($($t:ident)+) => {
367 $(
368 {
369 let x: $t = 10;
370 let y: $t = -3;
371 assert_eq!(Euclid::div_euclid(x, y), -3);
372 assert_eq!(Euclid::div_euclid(-x, y), 4);
373 assert_eq!(Euclid::rem_euclid(x, y), 1);
374 assert_eq!(Euclid::rem_euclid(-x, y), 2);
375 assert_eq!((Euclid::div_euclid(x, y), Euclid::rem_euclid(x, y)), Euclid::div_rem_euclid(x, y));
376 let x: $t = $t::MIN + 1;
377 let y: $t = -1;
378 assert_eq!(Euclid::div_euclid(x, y), $t::MAX);
379 }
380 )+
381 };
382 }
383
384 test_euclid!(isize i8 i16 i32 i64 i128);
385 }
386
387 #[test]
388 #[cfg(feature = "std")]
389 fn euclid_float() {
390 macro_rules! test_euclid {
391 ($($t:ident)+) => {
392 $(
393 {
394 let x: $t = 12.1;
395 let y: $t = 3.2;
396 assert!((Euclid::div_euclid(x, y) * y + Euclid::rem_euclid(x, y) - x).abs()
399 <= 46.4 * <$t>::EPSILON);
400 assert!((Euclid::div_euclid(x, -y) * -y + Euclid::rem_euclid(x, -y) - x).abs()
401 <= 46.4 * <$t>::EPSILON);
402 assert!((Euclid::div_euclid(-x, y) * y + Euclid::rem_euclid(-x, y) + x).abs()
403 <= 46.4 * <$t>::EPSILON);
404 assert!((Euclid::div_euclid(-x, -y) * -y + Euclid::rem_euclid(-x, -y) + x).abs()
405 <= 46.4 * <$t>::EPSILON);
406 assert_eq!((Euclid::div_euclid(x, y), Euclid::rem_euclid(x, y)), Euclid::div_rem_euclid(x, y));
407 }
408 )+
409 };
410 }
411
412 test_euclid!(f32 f64);
413 }
414
415 #[test]
416 fn euclid_wrapping_overflowing() {
417 assert_eq!(WrappingEuclid::wrapping_div_euclid(i8::MIN, -1), i8::MIN);
418 assert_eq!(WrappingEuclid::wrapping_rem_euclid(i8::MIN, -1), 0);
419 assert_eq!(WrappingEuclid::wrapping_div_euclid(-7i32, 4), -2);
420 assert_eq!(WrappingEuclid::wrapping_rem_euclid(-7i32, 4), 1);
421 assert_eq!(
422 OverflowingEuclid::overflowing_div_euclid(i8::MIN, -1),
423 (i8::MIN, true)
424 );
425 assert_eq!(
426 OverflowingEuclid::overflowing_rem_euclid(i8::MIN, -1),
427 (0, true)
428 );
429 assert_eq!(
430 OverflowingEuclid::overflowing_div_euclid(7u8, 4),
431 (1, false)
432 );
433 }
434
435 #[test]
436 fn euclid_checked() {
437 macro_rules! test_euclid_checked {
438 ($($t:ident)+) => {
439 $(
440 {
441 assert_eq!(CheckedEuclid::checked_div_euclid($t::MIN, -1), None);
442 assert_eq!(CheckedEuclid::checked_rem_euclid($t::MIN, -1), None);
443 assert_eq!(CheckedEuclid::checked_div_euclid(1, 0), None);
444 assert_eq!(CheckedEuclid::checked_rem_euclid(1, 0), None);
445 }
446 )+
447 };
448 }
449
450 test_euclid_checked!(isize i8 i16 i32 i64 i128);
451 }
452}