[go: up one dir, main page]

rug/
ops_prim.rs

1// Copyright © 2016–2025 Trevor Spiteri
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17use crate::Assign;
18#[allow(unused_imports)]
19use crate::ops::{
20    AddFrom, BitAndFrom, BitOrFrom, BitXorFrom, DivFrom, DivRounding, DivRoundingAssign,
21    DivRoundingFrom, MulFrom, NegAssign, NotAssign, Pow, PowAssign, PowFrom, RemFrom, RemRounding,
22    RemRoundingAssign, RemRoundingFrom, ShlFrom, ShrFrom, SubFrom,
23};
24use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub};
25#[cfg(feature = "std")]
26use std::borrow::Cow;
27
28macro_rules! assign_from {
29    ($T:ty; $op:ident; $Imp:ident $method:ident) => {
30        impl $Imp for $T {
31            #[inline]
32            fn $method(&mut self, lhs: $T) {
33                *self = lhs.$op(*self);
34            }
35        }
36        impl $Imp<&$T> for $T {
37            #[inline]
38            fn $method(&mut self, lhs: &$T) {
39                *self = (*lhs).$op(*self);
40            }
41        }
42    };
43}
44macro_rules! int_ops {
45    ($($T:ty)*) => { $(
46        impl Assign for $T {
47            #[inline]
48            fn assign(&mut self, src: $T) {
49                *self = src;
50            }
51        }
52        impl Assign<&$T> for $T {
53            #[inline]
54            fn assign(&mut self, src: &$T) {
55                *self = *src;
56            }
57        }
58        impl NotAssign for $T {
59            #[inline]
60            fn not_assign(&mut self) {
61                *self = !*self;
62            }
63        }
64        #[cfg(not(feature = "num-traits"))]
65        impl Pow<u32> for $T {
66            type Output = $T;
67            #[inline]
68            fn pow(self, rhs: u32) -> $T {
69                self.pow(rhs)
70            }
71        }
72        #[cfg(not(feature = "num-traits"))]
73        impl Pow<u32> for &$T {
74            type Output = $T;
75            #[inline]
76            fn pow(self, rhs: u32) -> $T {
77                (*self).pow(rhs)
78            }
79        }
80        #[cfg(not(feature = "num-traits"))]
81        impl Pow<&u32> for $T {
82            type Output = $T;
83            #[inline]
84            fn pow(self, rhs: &u32) -> $T {
85                self.pow(*rhs)
86            }
87        }
88        #[cfg(not(feature = "num-traits"))]
89        impl Pow<&u32> for &$T {
90            type Output = $T;
91            #[inline]
92            fn pow(self, rhs: &u32) -> $T {
93                (*self).pow(*rhs)
94            }
95        }
96        impl PowAssign<u32> for $T {
97            #[inline]
98            fn pow_assign(&mut self, rhs: u32) {
99                *self = self.pow(rhs);
100            }
101        }
102        impl PowAssign<&u32> for $T {
103            #[inline]
104            fn pow_assign(&mut self, rhs: &u32) {
105                *self = self.pow(*rhs);
106            }
107        }
108        assign_from! { $T; add; AddFrom add_from }
109        assign_from! { $T; sub; SubFrom sub_from }
110        assign_from! { $T; mul; MulFrom mul_from }
111        assign_from! { $T; div; DivFrom div_from }
112        assign_from! { $T; rem; RemFrom rem_from }
113        assign_from! { $T; bitand; BitAndFrom bitand_from }
114        assign_from! { $T; bitor; BitOrFrom bitor_from }
115        assign_from! { $T; bitxor; BitXorFrom bitxor_from }
116        assign_from! { $T; shl; ShlFrom shl_from }
117        assign_from! { $T; shr; ShrFrom shr_from }
118    )* };
119}
120macro_rules! int_neg {
121    ($($T:ty)*) => { $(
122        impl NegAssign for $T {
123            #[inline]
124            fn neg_assign(&mut self) {
125                *self = -*self;
126            }
127        }
128    )* };
129}
130macro_rules! float_ops {
131    ($($T:ty)*) => { $(
132        impl Assign for $T {
133            #[inline]
134            fn assign(&mut self, src: $T) {
135                *self = src;
136            }
137        }
138        impl Assign<&$T> for $T {
139            #[inline]
140            fn assign(&mut self, src: &$T) {
141                *self = *src;
142            }
143        }
144        impl NegAssign for $T {
145            #[inline]
146            fn neg_assign(&mut self) {
147                *self = -*self;
148            }
149        }
150        #[cfg(feature = "std")]
151        #[cfg(not(feature = "num-traits"))]
152        impl Pow<i32> for $T {
153            type Output = $T;
154            #[inline]
155            fn pow(self, rhs: i32) -> $T {
156                self.powi(rhs)
157            }
158        }
159        #[cfg(feature = "std")]
160        #[cfg(not(feature = "num-traits"))]
161        impl Pow<i32> for &$T {
162            type Output = $T;
163            #[inline]
164            fn pow(self, rhs: i32) -> $T {
165                self.powi(rhs)
166            }
167        }
168        #[cfg(feature = "std")]
169        #[cfg(not(feature = "num-traits"))]
170        impl Pow<&i32> for $T {
171            type Output = $T;
172            #[inline]
173            fn pow(self, rhs: &i32) -> $T {
174                self.powi(*rhs)
175            }
176        }
177        #[cfg(feature = "std")]
178        #[cfg(not(feature = "num-traits"))]
179        impl Pow<&i32> for &$T {
180            type Output = $T;
181            #[inline]
182            fn pow(self, rhs: &i32) -> $T {
183                self.powi(*rhs)
184            }
185        }
186        #[cfg(feature = "std")]
187        impl PowAssign<i32> for $T {
188            #[inline]
189            fn pow_assign(&mut self, rhs: i32) {
190                *self = self.powi(rhs);
191            }
192        }
193        #[cfg(feature = "std")]
194        impl PowAssign<&i32> for $T {
195            #[inline]
196            fn pow_assign(&mut self, rhs: &i32) {
197                *self = self.powi(*rhs);
198            }
199        }
200        #[cfg(feature = "std")]
201        #[cfg(not(feature = "num-traits"))]
202        impl Pow<$T> for $T {
203            type Output = $T;
204            #[inline]
205            fn pow(self, rhs: $T) -> $T {
206                self.powf(rhs)
207            }
208        }
209        #[cfg(feature = "std")]
210        #[cfg(not(feature = "num-traits"))]
211        impl Pow<$T> for &$T {
212            type Output = $T;
213            #[inline]
214            fn pow(self, rhs: $T) -> $T {
215                self.powf(rhs)
216            }
217        }
218        #[cfg(feature = "std")]
219        #[cfg(not(feature = "num-traits"))]
220        impl Pow<&$T> for $T {
221            type Output = $T;
222            #[inline]
223            fn pow(self, rhs: &$T) -> $T {
224                self.powf(*rhs)
225            }
226        }
227        #[cfg(feature = "std")]
228        #[cfg(not(feature = "num-traits"))]
229        impl Pow<&$T> for &$T {
230            type Output = $T;
231            #[inline]
232            fn pow(self, rhs: &$T) -> $T {
233                self.powf(*rhs)
234            }
235        }
236        #[cfg(feature = "std")]
237        impl PowAssign<$T> for $T {
238            #[inline]
239            fn pow_assign(&mut self, rhs: $T) {
240                *self = self.powf(rhs);
241            }
242        }
243        #[cfg(feature = "std")]
244        impl PowAssign<&$T> for $T {
245            #[inline]
246            fn pow_assign(&mut self, rhs: &$T) {
247                *self = self.powf(*rhs);
248            }
249        }
250        assign_from! { $T; add; AddFrom add_from }
251        assign_from! { $T; sub; SubFrom sub_from }
252        assign_from! { $T; mul; MulFrom mul_from }
253        assign_from! { $T; div; DivFrom div_from }
254        assign_from! { $T; rem; RemFrom rem_from }
255        #[cfg(feature = "std")]
256        assign_from! { $T; pow; PowFrom pow_from }
257    )* };
258}
259
260macro_rules! rounding_fill {
261    (
262        $T:ty,
263        $Imp:ident
264        $ImpAssign:ident
265        $ImpFrom:ident,
266        $trunc:ident
267        $ceil:ident
268        $floor:ident
269        $euc:ident,
270        $trunc_ass:ident
271        $ceil_ass:ident
272        $floor_ass:ident
273        $euc_ass:ident,
274        $trunc_from:ident
275        $ceil_from:ident
276        $floor_from:ident
277        $euc_from:ident
278    ) => {
279        #[cfg(feature = "std")]
280        impl $Imp<&$T> for $T {
281            type Output = <$T as $Imp>::Output;
282            #[inline]
283            fn $trunc(self, rhs: &$T) -> Self::Output {
284                $Imp::$trunc(self, *rhs)
285            }
286            #[inline]
287            fn $ceil(self, rhs: &$T) -> Self::Output {
288                $Imp::$ceil(self, *rhs)
289            }
290            #[inline]
291            fn $floor(self, rhs: &$T) -> Self::Output {
292                $Imp::$floor(self, *rhs)
293            }
294            #[inline]
295            fn $euc(self, rhs: &$T) -> Self::Output {
296                $Imp::$euc(self, *rhs)
297            }
298        }
299
300        #[cfg(feature = "std")]
301        impl $Imp<$T> for &$T {
302            type Output = <$T as $Imp>::Output;
303            #[inline]
304            fn $trunc(self, rhs: $T) -> Self::Output {
305                $Imp::$trunc(*self, rhs)
306            }
307            #[inline]
308            fn $ceil(self, rhs: $T) -> Self::Output {
309                $Imp::$ceil(*self, rhs)
310            }
311            #[inline]
312            fn $floor(self, rhs: $T) -> Self::Output {
313                $Imp::$floor(*self, rhs)
314            }
315            #[inline]
316            fn $euc(self, rhs: $T) -> Self::Output {
317                $Imp::$euc(*self, rhs)
318            }
319        }
320
321        #[cfg(feature = "std")]
322        impl $Imp<&$T> for &$T {
323            type Output = <$T as $Imp>::Output;
324            #[inline]
325            fn $trunc(self, rhs: &$T) -> Self::Output {
326                $Imp::$trunc(*self, *rhs)
327            }
328            #[inline]
329            fn $ceil(self, rhs: &$T) -> Self::Output {
330                $Imp::$ceil(*self, *rhs)
331            }
332            #[inline]
333            fn $floor(self, rhs: &$T) -> Self::Output {
334                $Imp::$floor(*self, *rhs)
335            }
336            #[inline]
337            fn $euc(self, rhs: &$T) -> Self::Output {
338                $Imp::$euc(*self, *rhs)
339            }
340        }
341
342        #[cfg(feature = "std")]
343        impl $ImpAssign for $T {
344            #[inline]
345            fn $trunc_ass(&mut self, rhs: $T) {
346                *self = $Imp::$trunc(*self, rhs);
347            }
348            #[inline]
349            fn $ceil_ass(&mut self, rhs: $T) {
350                *self = $Imp::$ceil(*self, rhs);
351            }
352            #[inline]
353            fn $floor_ass(&mut self, rhs: $T) {
354                *self = $Imp::$floor(*self, rhs);
355            }
356            #[inline]
357            fn $euc_ass(&mut self, rhs: $T) {
358                *self = $Imp::$euc(*self, rhs);
359            }
360        }
361
362        #[cfg(feature = "std")]
363        impl $ImpAssign<&$T> for $T {
364            #[inline]
365            fn $trunc_ass(&mut self, rhs: &$T) {
366                *self = $Imp::$trunc(*self, *rhs);
367            }
368            #[inline]
369            fn $ceil_ass(&mut self, rhs: &$T) {
370                *self = $Imp::$ceil(*self, *rhs);
371            }
372            #[inline]
373            fn $floor_ass(&mut self, rhs: &$T) {
374                *self = $Imp::$floor(*self, *rhs);
375            }
376            #[inline]
377            fn $euc_ass(&mut self, rhs: &$T) {
378                *self = $Imp::$euc(*self, *rhs);
379            }
380        }
381
382        #[cfg(feature = "std")]
383        impl $ImpFrom for $T {
384            #[inline]
385            fn $trunc_from(&mut self, lhs: $T) {
386                *self = $Imp::$trunc(lhs, *self);
387            }
388            #[inline]
389            fn $ceil_from(&mut self, lhs: $T) {
390                *self = $Imp::$ceil(lhs, *self);
391            }
392            #[inline]
393            fn $floor_from(&mut self, lhs: $T) {
394                *self = $Imp::$floor(lhs, *self);
395            }
396            #[inline]
397            fn $euc_from(&mut self, lhs: $T) {
398                *self = $Imp::$euc(lhs, *self);
399            }
400        }
401
402        #[cfg(feature = "std")]
403        impl $ImpFrom<&$T> for $T {
404            #[inline]
405            fn $trunc_from(&mut self, lhs: &$T) {
406                *self = $Imp::$trunc(*lhs, *self);
407            }
408            #[inline]
409            fn $ceil_from(&mut self, lhs: &$T) {
410                *self = $Imp::$ceil(*lhs, *self);
411            }
412            #[inline]
413            fn $floor_from(&mut self, lhs: &$T) {
414                *self = $Imp::$floor(*lhs, *self);
415            }
416            #[inline]
417            fn $euc_from(&mut self, lhs: &$T) {
418                *self = $Imp::$euc(*lhs, *self);
419            }
420        }
421    };
422}
423
424macro_rules! rounding_signed {
425    ($($T:ty)*) => { $(
426        impl DivRounding for $T {
427            type Output = $T;
428            #[inline]
429            fn div_trunc(self, rhs: $T) -> $T {
430                self / rhs
431            }
432            #[inline]
433            fn div_ceil(self, rhs: $T) -> $T {
434                let (q, r) = (self / rhs, self % rhs);
435                let change = if rhs > 0 { r > 0 } else { r < 0 };
436                if change {
437                    q + 1
438                } else {
439                    q
440                }
441            }
442            #[inline]
443            fn div_floor(self, rhs: $T) -> $T {
444                let (q, r) = (self / rhs, self % rhs);
445                let change = if rhs > 0 { r < 0 } else { r > 0 };
446                if change {
447                    q - 1
448                } else {
449                    q
450                }
451            }
452            #[inline]
453            fn div_euc(self, rhs: $T) -> $T {
454                let (q, r) = (self / rhs, self % rhs);
455                if r < 0 {
456                    if rhs < 0 {
457                        q + 1
458                    } else {
459                        q - 1
460                    }
461                } else {
462                    q
463                }
464            }
465        }
466
467        rounding_fill! {
468            $T,
469            DivRounding DivRoundingAssign DivRoundingFrom,
470            div_trunc div_ceil div_floor div_euc,
471            div_trunc_assign div_ceil_assign div_floor_assign div_euc_assign,
472            div_trunc_from div_ceil_from div_floor_from div_euc_from
473        }
474
475        impl RemRounding for $T {
476            type Output = $T;
477            #[inline]
478            fn rem_trunc(self, rhs: $T) -> $T {
479                self % rhs
480            }
481            #[inline]
482            fn rem_ceil(self, rhs: $T) -> $T {
483                let r = self % rhs;
484                let change = if rhs > 0 { r > 0 } else { r < 0 };
485                if change {
486                    r - rhs
487                } else {
488                    r
489                }
490            }
491            #[inline]
492            fn rem_floor(self, rhs: $T) -> $T {
493                let r = self % rhs;
494                let change = if rhs > 0 { r < 0 } else { r > 0 };
495                if change {
496                    r + rhs
497                } else {
498                    r
499                }
500            }
501            #[inline]
502            fn rem_euc(self, rhs: $T) -> $T {
503                let r = self % rhs;
504                if r < 0 {
505                    if rhs < 0 {
506                        r - rhs
507                    } else {
508                        r + rhs
509                    }
510                } else {
511                    r
512                }
513            }
514        }
515
516        rounding_fill! {
517            $T,
518            RemRounding RemRoundingAssign RemRoundingFrom,
519            rem_trunc rem_ceil rem_floor rem_euc,
520            rem_trunc_assign rem_ceil_assign rem_floor_assign rem_euc_assign,
521            rem_trunc_from rem_ceil_from rem_floor_from rem_euc_from
522        }
523
524    )* };
525}
526
527macro_rules! rounding_unsigned {
528    ($($T:ty)*) => { $(
529        impl DivRounding for $T {
530            type Output = $T;
531            #[inline]
532            fn div_trunc(self, rhs: $T) -> $T {
533                self / rhs
534            }
535            #[inline]
536            fn div_ceil(self, rhs: $T) -> $T {
537                let (q, r) = (self / rhs, self % rhs);
538                if r > 0 {
539                    q + 1
540                } else {
541                    q
542                }
543            }
544            #[inline]
545            fn div_floor(self, rhs: $T) -> $T {
546                self / rhs
547            }
548            #[inline]
549            fn div_euc(self, rhs: $T) -> $T {
550                self / rhs
551            }
552        }
553
554        rounding_fill! {
555            $T,
556            DivRounding DivRoundingAssign DivRoundingFrom,
557            div_trunc div_ceil div_floor div_euc,
558            div_trunc_assign div_ceil_assign div_floor_assign div_euc_assign,
559            div_trunc_from div_ceil_from div_floor_from div_euc_from
560        }
561    )* };
562}
563
564macro_rules! rounding_float {
565    ($($T:ty)*) => { $(
566        #[cfg(feature = "std")]
567        impl DivRounding for $T {
568            type Output = $T;
569            #[inline]
570            fn div_trunc(self, rhs: $T) -> $T {
571                (self / rhs).trunc()
572            }
573            #[inline]
574            fn div_ceil(self, rhs: $T) -> $T {
575                let (q, r) = ((self / rhs).trunc(), self % rhs);
576                let change = if rhs > 0.0 { r > 0.0 } else { r < 0.0 };
577                if change {
578                    q + 1.0
579                } else {
580                    q
581                }
582            }
583            #[inline]
584            fn div_floor(self, rhs: $T) -> $T {
585                let (q, r) = ((self / rhs).trunc(), self % rhs);
586                let change = if rhs > 0.0 { r < 0.0 } else { r > 0.0 };
587                if change {
588                    q - 1.0
589                } else {
590                    q
591                }
592            }
593            #[inline]
594            fn div_euc(self, rhs: $T) -> $T {
595                let (q, r) = ((self / rhs).trunc(), self % rhs);
596                if r < 0.0 {
597                    if rhs < 0.0 {
598                        q + 1.0
599                    } else {
600                        q - 1.0
601                    }
602                } else {
603                    q
604                }
605            }
606        }
607
608        rounding_fill! {
609            $T,
610            DivRounding DivRoundingAssign DivRoundingFrom,
611            div_trunc div_ceil div_floor div_euc,
612            div_trunc_assign div_ceil_assign div_floor_assign div_euc_assign,
613            div_trunc_from div_ceil_from div_floor_from div_euc_from
614        }
615
616        impl RemRounding for $T {
617            type Output = $T;
618            #[inline]
619            fn rem_trunc(self, rhs: $T) -> $T {
620                self % rhs
621            }
622            #[inline]
623            fn rem_ceil(self, rhs: $T) -> $T {
624                let r = self % rhs;
625                let change = if rhs > 0.0 { r > 0.0 } else { r < 0.0 };
626                if change {
627                    r - rhs
628                } else {
629                    r
630                }
631            }
632            #[inline]
633            fn rem_floor(self, rhs: $T) -> $T {
634                let r = self % rhs;
635                let change = if rhs > 0.0 { r < 0.0 } else { r > 0.0 };
636                if change {
637                    r + rhs
638                } else {
639                    r
640                }
641            }
642            #[inline]
643            fn rem_euc(self, rhs: $T) -> $T {
644                let r = self % rhs;
645                if r < 0.0 {
646                    if rhs < 0.0 {
647                        r - rhs
648                    } else {
649                        r + rhs
650                    }
651                } else {
652                    r
653                }
654            }
655        }
656
657        rounding_fill! {
658            $T,
659            RemRounding RemRoundingAssign RemRoundingFrom,
660            rem_trunc rem_ceil rem_floor rem_euc,
661            rem_trunc_assign rem_ceil_assign rem_floor_assign rem_euc_assign,
662            rem_trunc_from rem_ceil_from rem_floor_from rem_euc_from
663        }
664
665    )* };
666}
667
668impl NotAssign for bool {
669    #[inline]
670    fn not_assign(&mut self) {
671        *self = !*self;
672    }
673}
674assign_from! { bool; bitand; BitAndFrom bitand_from }
675assign_from! { bool; bitor; BitOrFrom bitor_from }
676assign_from! { bool; bitxor; BitXorFrom bitxor_from }
677
678int_ops! { i8 i16 i32 i64 i128 isize }
679int_ops! { u8 u16 u32 u64 u128 usize }
680int_neg! { i8 i16 i32 i64 i128 isize }
681assign_from! { u32; pow; PowFrom pow_from }
682float_ops! { f32 f64 }
683
684rounding_signed! { i8 i16 i32 i64 i128 isize }
685
686// For unsigned primitives, RemRounding is not implemented. Ignoring
687// the issue that we cannot have negative numbers, if r == n % d then
688//
689// n.rem_trunc(d) -> r
690// n.rem_ceil(d) -> if r > 0 { r - d } else { 0 }
691// n.rem_floor(d) -> r
692// n.rem_euc(d) -> r
693
694rounding_unsigned! { u8 u16 u32 u64 u128 usize }
695
696rounding_float! { f32 f64 }
697
698#[cfg(feature = "std")]
699impl Assign<&str> for String {
700    #[inline]
701    fn assign(&mut self, src: &str) {
702        self.clear();
703        self.push_str(src);
704    }
705}
706
707#[cfg(feature = "std")]
708impl<'a> Assign<&'a str> for Cow<'a, str> {
709    #[inline]
710    fn assign(&mut self, src: &'a str) {
711        *self = Cow::Borrowed(src);
712    }
713}
714
715#[cfg(feature = "std")]
716impl<'a> Assign<Cow<'a, str>> for Cow<'a, str> {
717    #[inline]
718    fn assign(&mut self, src: Cow<'a, str>) {
719        *self = src;
720    }
721}
722
723#[cfg(feature = "std")]
724impl AddFrom<&str> for String {
725    #[inline]
726    fn add_from(&mut self, lhs: &str) {
727        self.insert_str(0, lhs);
728    }
729}
730
731#[cfg(feature = "std")]
732impl<'a> AddFrom<&'a str> for Cow<'a, str> {
733    fn add_from(&mut self, lhs: &'a str) {
734        if lhs.is_empty() {
735        } else if self.is_empty() {
736            *self = Cow::Borrowed(lhs);
737        } else {
738            match *self {
739                Cow::Borrowed(rhs) => {
740                    let mut s = String::with_capacity(lhs.len() + rhs.len());
741                    s.push_str(lhs);
742                    s.push_str(rhs);
743                    *self = Cow::Owned(s);
744                }
745                Cow::Owned(ref mut s) => {
746                    s.insert_str(0, lhs);
747                }
748            }
749        }
750    }
751}
752
753#[cfg(feature = "std")]
754impl<'a> AddFrom<Cow<'a, str>> for Cow<'a, str> {
755    fn add_from(&mut self, lhs: Cow<'a, str>) {
756        if lhs.is_empty() {
757        } else if self.is_empty() {
758            *self = lhs;
759        } else {
760            match *self {
761                Cow::Borrowed(rhs) => {
762                    let mut s = String::with_capacity(lhs.len() + rhs.len());
763                    s.push_str(&lhs);
764                    s.push_str(rhs);
765                    *self = Cow::Owned(s);
766                }
767                Cow::Owned(ref mut s) => {
768                    s.insert_str(0, &lhs);
769                }
770            }
771        }
772    }
773}