inertia_core/
macros.rs

1/*
2 *  Copyright (C) 2021 William Youmans
3 *
4 *  This program is free software: you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation, either version 3 of the License, or
7 *  (at your option) any later version.
8 *
9 *  This program is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 */
17
18// TODO: op guards need work, especially *From and Assign* (DivFrom, AssignDiv etc)
19//! Macros for implementing comparisons, operations, and conversions.
20
21macro_rules! default {
22    // Unary ops and From
23    ($op:ident, ctx, $out_ty:ident, $in:ident) => {
24        $out_ty::zero($in.context())
25    };
26    ($op:ident, ctx_in, $out_ty:ident, $in:ident) => {
27        $out_ty::zero()
28    };
29    ($op:ident, matrix, $out_ty:ident, $in:ident) => {
30        $out_ty::zero($in.nrows_si(), $in.ncols_si())
31    };
32    ($op:ident, matrix_ctx, $out_ty:ident, $in:ident) => {
33        $out_ty::zero($in.nrows_si(), $in.ncols_si(), $in.context())
34    };
35    ($op:ident, matrix_ctx_new_only, $out_ty:ident, $in:ident) => {
36        $out_ty::zero($in.nrows_si(), $in.ncols_si(), $in.context())
37    };
38    ($op:ident, $kw:ident, $out_ty:ident, $in:ident) => {
39        $out_ty::default()
40    };
41
42    // Binary ops
43    ($op:ident, ctx, $out_ty:ident, $lhs:ident, $rhs:ident) => {
44        $out_ty::zero($lhs.context())
45    };
46    ($op:ident, ctx_lhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
47        $out_ty::zero($lhs.context())
48    };
49    ($op:ident, ctx_rhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
50        $out_ty::zero($rhs.context())
51    };
52    ($op:ident, matrix, $out_ty:ident, $lhs:ident, $rhs:ident) => {
53        $out_ty::zero($lhs.nrows_si(), $rhs.ncols_si())
54    };
55    ($op:ident, matrix_ctx, $out_ty:ident, $lhs:ident, $rhs:ident) => {
56        $out_ty::zero($lhs.nrows_si(), $rhs.ncols_si(), $lhs.context())
57    };
58    /*
59    ($op:ident, matrix_ctx_lhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
60        $out_ty::zero($lhs.nrows_si(), $rhs.ncols_si(), $lhs.context())
61    };
62    ($op:ident, matrix_ctx_rhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
63        $out_ty::zero($lhs.nrows_si(), $rhs.ncols_si(), $rhs.context())
64    };
65    */
66    ($op:ident, matrix_ctx_new_only, $out_ty:ident, $lhs:ident, $rhs:ident) => {
67        $out_ty::zero($lhs.nrows_si(), $rhs.ncols_si(), $lhs.context())
68    };
69    ($op:ident, scalar_lhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
70        $out_ty::zero($rhs.nrows_si(), $rhs.ncols_si())
71    };
72    ($op:ident, scalar_rhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
73        $out_ty::zero($lhs.nrows_si(), $lhs.ncols_si())
74    };
75    ($op:ident, $kw:ident, $out_ty:ident, $lhs:ident, $rhs:ident) => {
76        $out_ty::default()
77    };
78}
79
80macro_rules! op_guard {
81    // Unary ops and From
82    (Inv, $kw:ident, $out_ty:ident, $in:ident) => {
83        // TODO: check den != 0
84        //$in.is_invertible()
85    };
86    (Pow, $kw:ident, $out_ty:ident, $in:ident) => {
87        // TODO: check if exp negative or fractional for certain types
88    };
89    ($op:ident, $kw:ident, $out_ty:ident, $in:ident) => {
90    };
91
92    // Binary ops
93    ($op:ident, ctx, $out_ty:ident, $lhs:ident, $rhs:ident) => {
94        // check contexts agree
95        assert_eq!($lhs.context(), $rhs.context())
96    };
97    (Mul, matrix, $out_ty:ident, $lhs:ident, $rhs:ident) => {
98        assert_eq!($lhs.ncols_si(), $rhs.nrows_si())
99    };
100    (MulAssign, matrix, $out_ty:ident, $lhs:ident, $rhs:ident) => {
101        assert_eq!($lhs.ncols_si(), $rhs.nrows_si())
102    };
103    // covers all matrix ops except Mul
104    ($op:ident, matrix, $out_ty:ident, $lhs:ident, $rhs:ident) => {
105        assert_eq!($lhs.nrows_si(), $rhs.nrows_si());
106        assert_eq!($lhs.ncols_si(), $rhs.ncols_si())
107    };
108    ($op:ident, scalar_lhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
109    };
110    (Div, scalar_rhs, $out_ty:ident, $lhs:ident, $rhs:ident) => {
111        // TODO:
112        // $rhs.is_invertible()
113    };
114    ($op:ident, $kw:ident, $out_ty:ident, $lhs:ident, $rhs:ident) => {
115    };
116}
117
118macro_rules! call_unsafe {
119    // Unary ops and From
120    (ctx, $func:path, $out:ident, $in:ident) => {
121        unsafe {
122            $func($out.as_mut_ptr(), $in.as_ptr(), $out.ctx_as_ptr());
123        }
124    };
125    (matrix_ctx, $func:path, $out:ident, $in:ident) => {
126        unsafe {
127            $func($out.as_mut_ptr(), $in.as_ptr(), $out.ctx_as_ptr());
128        }
129    };
130    (ctx_in, $func:path, $out:ident, $in:ident) => {
131        unsafe {
132            $func($out.as_mut_ptr(), $in.as_ptr(), $in.ctx_as_ptr());
133        }
134    };
135    ($kw:ident, $func:path, $out:ident, $in:ident) => {
136        unsafe {
137            $func($out.as_mut_ptr(), $in.as_ptr());
138        }
139    };
140    (cast ctx, $func:path, $cast:ty, $out:ident, $in:ident) => {
141        unsafe {
142            $func($out.as_mut_ptr(), *$in as $cast, $out.ctx_as_ptr());
143        }
144    };
145    (cast $kw:ident, $func:path, $cast:ty, $out:ident, $in:ident) => {
146        unsafe {
147            $func($out.as_mut_ptr(), *$in as $cast);
148        }
149    };
150
151    // Binary ops
152    (ctx, $func:path, $out:ident, $lhs:ident, $rhs:ident) => {
153        unsafe {
154            $func(
155                $out.as_mut_ptr(),
156                $lhs.as_ptr(),
157                $rhs.as_ptr(),
158                $lhs.ctx_as_ptr(),
159            );
160        }
161    };
162    (ctx_lhs, $func:path, $out:ident, $lhs:ident, $rhs:ident) => {
163        unsafe {
164            $func(
165                $out.as_mut_ptr(),
166                $lhs.as_ptr(),
167                $rhs.as_ptr(),
168                $lhs.ctx_as_ptr(),
169            );
170        }
171    };
172    (ctx_rhs, $func:path, $out:ident, $lhs:ident, $rhs:ident) => {
173        unsafe {
174            $func(
175                $out.as_mut_ptr(),
176                $lhs.as_ptr(),
177                $rhs.as_ptr(),
178                $rhs.ctx_as_ptr(),
179            );
180        }
181    };
182    (matrix_ctx, $func:path, $out:ident, $lhs:ident, $rhs:ident) => {
183        unsafe {
184            $func(
185                $out.as_mut_ptr(),
186                $lhs.as_ptr(),
187                $rhs.as_ptr(),
188                $lhs.ctx_as_ptr(),
189            );
190        }
191    };
192    ($kw:ident, $func:path, $out:ident, $lhs:ident, $rhs:ident) => {
193        unsafe {
194            $func($out.as_mut_ptr(), $lhs.as_ptr(), $rhs.as_ptr());
195        }
196    };
197
198    // Binary ops with primitive types
199    (cast_rhs ctx_lhs, $func:path, $cast:ty, $out:ident, $lhs:ident, $rhs:ident) => {
200        unsafe {
201            $func(
202                $out.as_mut_ptr(),
203                $lhs.as_ptr(),
204                *$rhs as $cast,
205                $lhs.ctx_as_ptr(),
206            );
207        }
208    };
209    (cast_rhs $kw:ident, $func:path, $cast:ty, $out:ident, $lhs:ident, $rhs:ident) => {
210        unsafe {
211            $func($out.as_mut_ptr(), $lhs.as_ptr(), *$rhs as $cast);
212        }
213    };
214    (cast_lhs ctx_rhs, $func:path, $cast:ty, $out:ident, $lhs:ident, $rhs:ident) => {
215        unsafe {
216            $func(
217                $out.as_mut_ptr(),
218                *$lhs as $cast,
219                $rhs.as_ptr(),
220                $rhs.ctx_as_ptr(),
221            );
222        }
223    };
224    (cast_lhs $kw:ident, $func:path, $cast:ty, $out:ident, $lhs:ident, $rhs:ident) => {
225        unsafe {
226            $func($out.as_mut_ptr(), *$lhs as $cast, $rhs.as_ptr());
227        }
228    };
229}
230
231/// Macros for overloading comparison operators
232#[macro_export]
233macro_rules! impl_cmp {
234    // a = a
235    (
236        eq
237        $t:ident
238        {
239            $($code:tt)*
240        }
241    ) => {
242        impl Eq for $t {}
243
244        //impl Eq for &$t {}
245
246        impl PartialEq for $t {
247            #[inline]
248            $($code)*
249        }
250
251        impl PartialEq<&$t> for $t {
252            #[inline]
253            fn eq(&self, rhs: &&$t) -> bool {
254                rhs.eq(&self)
255            }
256        }
257
258        impl PartialEq<$t> for &$t {
259            #[inline]
260            fn eq(&self, rhs: &$t) -> bool {
261                self.eq(&rhs)
262            }
263        }
264    };
265    (
266        partial_eq
267        $t:ident
268        {
269            $($code:tt)*
270        }
271    ) => {
272        impl_cmp! {
273            partial_eq
274            $t, $t
275            {
276                $($code)*
277            }
278        }
279    };
280    // a > a
281    (
282        ord
283        $t:ident
284        {
285            $($code:tt)*
286        }
287    ) => {
288        impl Ord for $t {
289            #[inline]
290            $($code)*
291        }
292
293        impl PartialOrd for $t {
294            #[inline]
295            fn partial_cmp(&self, rhs: &$t) -> Option<Ordering> {
296                Some(self.cmp(rhs))
297            }
298        }
299    };
300    (
301        partial_ord
302        $t:ident
303        {
304            $($code:tt)*
305        }
306    ) => {
307        impl_cmp! {
308            partial_ord
309            $t, $t
310            {
311                $($code)*
312            }
313        }
314    };
315    // a = b
316    (
317        partial_eq
318        $t1:ident, $t2:ident
319        {
320            $($code:tt)*
321        }
322    ) => {
323        impl PartialEq<$t2> for $t1 {
324            #[inline]
325            $($code)*
326        }
327
328        impl PartialEq<&$t2> for $t1 {
329            #[inline]
330            fn eq(&self, rhs: &&$t2) -> bool {
331                (&self).eq(rhs)
332            }
333        }
334
335        impl PartialEq<$t2> for &$t1 {
336            #[inline]
337            fn eq(&self, rhs: &$t2) -> bool {
338                self.eq(&rhs)
339            }
340        }
341    };
342    // a > b
343    (
344        partial_ord
345        $t1:ident, $t2:ident
346        {
347            $($code:tt)*
348        }
349    ) => {
350        impl PartialOrd<$t2> for $t1 {
351            #[inline]
352            $($code)*
353        }
354    };
355
356}
357
358/// Macros for overloading comparison operators with unsafe functions.
359macro_rules! impl_cmp_unsafe {
360    (
361        eq
362        $t:ident
363        $func:path
364    ) => {
365        impl_cmp! {
366            eq
367            $t
368            {
369                fn eq(&self, rhs: &$t) -> bool {
370                    unsafe { $func(self.as_ptr(), rhs.as_ptr()) != 0 }
371                }
372            }
373        }
374    };
375    (
376        partial_eq
377        $t1:ident, $t2:ident
378        $func:path
379    ) => {
380        impl_cmp! {
381            partial_eq
382            $t1, $t2
383            {
384                fn eq(&self, rhs: &$t2) -> bool {
385                    unsafe { $func(self.as_ptr(), rhs.as_ptr()) != 0 }
386                }
387            }
388        }
389        impl_cmp! {
390            partial_eq
391            $t2, $t1
392            {
393                fn eq(&self, rhs: &$t1) -> bool {
394                    unsafe { $func(rhs.as_ptr(), self.as_ptr()) != 0 }
395                }
396            }
397        }
398    };
399    (
400        partial_eq
401        $t1:ident, $cast:ident {$($t2:ident)+}
402        $func:path
403    ) => ($(
404        impl_cmp! {
405            partial_eq
406            $t1, $t2
407            {
408                fn eq(&self, rhs: &$t2) -> bool {
409                    unsafe { $func(self.as_ptr(), *rhs as $cast) != 0 }
410                }
411            }
412        }
413        impl_cmp! {
414            partial_eq
415            $t2, $t1
416            {
417                fn eq(&self, rhs: &$t1) -> bool {
418                    unsafe { $func(rhs.as_ptr(), *self as $cast) != 0 }
419                }
420            }
421        }
422    )+);
423    (
424        ord
425        $t:ident
426        $func:path
427    ) => {
428        impl_cmp! {
429            ord
430            $t
431            {
432                fn cmp(&self, rhs: &$t) -> Ordering {
433                    let cmp = unsafe { $func(self.as_ptr(), rhs.as_ptr()) };
434                    if cmp == 0 {
435                        Equal
436                    } else if cmp < 0 {
437                        Less
438                    } else {
439                        Greater
440                    }
441                }
442            }
443        }
444    };
445    (
446        partial_ord
447        $t1:ident, $t2:ident
448        $func:path
449    ) => {
450        impl_cmp! {
451            partial_ord
452            $t1, $t2
453            {
454                fn partial_cmp(&self, rhs: &$t2) -> Option<Ordering> {
455                    let cmp = unsafe { $func(self.as_ptr(), rhs.as_ptr()) };
456                    if cmp == 0 {
457                        Some(Equal)
458                    } else if cmp < 0 {
459                        Some(Less)
460                    } else {
461                        Some(Greater)
462                    }
463                }
464            }
465        }
466        impl_cmp! {
467            partial_ord
468            $t2, $t1
469            {
470                fn partial_cmp(&self, rhs: &$t1) -> Option<Ordering> {
471                    let cmp = unsafe { $func(rhs.as_ptr(), self.as_ptr()) };
472                    if cmp == 0 {
473                        Some(Equal)
474                    } else if cmp > 0 {
475                        Some(Less)
476                    } else {
477                        Some(Greater)
478                    }
479                }
480            }
481        }
482    };
483    (
484        partial_ord
485        $t1:ident, $cast:ident {$($t2:ident)+}
486        $func:path
487    ) => ($(
488        impl_cmp! {
489            partial_ord
490            $t1, $t2
491            {
492                fn partial_cmp(&self, rhs: &$t2) -> Option<Ordering> {
493                    let cmp = unsafe { $func(self.as_ptr(), *rhs as $cast) };
494                    if cmp == 0 {
495                        Some(Equal)
496                    } else if cmp < 0 {
497                        Some(Less)
498                    } else {
499                        Some(Greater)
500                    }
501                }
502            }
503        }
504        impl_cmp! {
505            partial_ord
506            $t2, $t1
507            {
508                fn partial_cmp(&self, rhs: &$t1) -> Option<Ordering> {
509                    let cmp = unsafe { $func(rhs.as_ptr(), *self as $cast) };
510                    if cmp == 0 {
511                        Some(Equal)
512                    } else if cmp > 0 {
513                        Some(Less)
514                    } else {
515                        Some(Greater)
516                    }
517                }
518            }
519        }
520    )+)
521}
522
523/// Macros for overloading unary operators.
524#[macro_export]
525macro_rules! impl_unop {
526    (
527        // assign
528        $t:ident
529        $op:ident {$meth:ident}
530        {
531            $($code:tt)*
532        }
533        $op_assign:ident {$meth_assign:ident}
534        {
535            $($code_assign:tt)*
536        }
537    ) => {
538        impl $op for $t {
539            type Output = $t;
540            #[inline]
541            fn $meth(mut self) -> $t {
542                self.$meth_assign();
543                self
544            }
545        }
546
547        impl $op for &$t {
548            type Output = $t;
549            #[inline]
550            $($code)*
551        }
552
553        impl $op_assign for $t {
554            #[inline]
555            $($code_assign)*
556        }
557    };
558    (
559        // no assign
560        $t:ident, $out:ident
561        $op:ident {$meth:ident}
562        {
563            $($code:tt)*
564        }
565    ) => {
566        impl $op for $t {
567            type Output = $out;
568            #[inline]
569            $($code)*
570        }
571
572        impl $op for &$t {
573            type Output = $out;
574            #[inline]
575            $($code)*
576        }
577    };
578    (
579        // no assign
580        $t:ident, Option<$out:ident>
581        $op:ident {$meth:ident}
582        {
583            $($code:tt)*
584        }
585    ) => {
586        impl $op for $t {
587            type Output = Option<$out>;
588            #[inline]
589            $($code)*
590        }
591
592        impl $op for &$t {
593            type Output = Option<$out>;
594            #[inline]
595            $($code)*
596        }
597    };
598}
599
600/// Macros for overloading unary operators with unsafe functions.
601macro_rules! impl_unop_unsafe {
602    (
603        $kw:ident
604        $t:ident
605        $op:ident {$meth:ident}
606        $op_assign:ident {$meth_assign:ident}
607        $func:path
608    ) => {
609        impl_unop! {
610            $t
611            $op {$meth}
612            {
613                fn $meth(self) -> $t {
614                    let mut res = default!($op, $kw, $t, self);
615                    call_unsafe!($kw, $func, res, self);
616                    res
617                }
618            }
619            $op_assign {$meth_assign}
620            {
621                fn $meth_assign(&mut self) {
622                    call_unsafe!($kw, $func, self, self);
623                }
624            }
625        }
626    };
627    (
628        $kw:ident
629        $t:ident, $out:ident
630        $op:ident {$meth:ident}
631        $func:path
632    ) => {
633        impl_unop! {
634            $t, $out
635            $op {$meth}
636            {
637                fn $meth(self) -> $out {
638                    let mut res = default!($op, $kw, $out, self);
639                    //unsafe { $func(res.as_mut_ptr(), self.as_ptr()); }
640                    call_unsafe!($kw, $func, res, self);
641                    res
642                }
643            }
644        }
645    };
646}
647
648/// Macros for overloading binary operators.
649#[macro_export]
650macro_rules! impl_binop {
651    (
652        // a + a = a
653        $t1:ident, $t2:ident, $out:ident
654        $(
655            $op:ident {$meth:ident}
656            {
657                $($code:tt)*
658            }
659            $op_assign:ident {$meth_assign:ident}
660            {
661                $($code_assign:tt)*
662            }
663            $op_from:ident {$meth_from:ident}
664            {
665                $($code_from:tt)*
666            }
667            $assign_op:ident {$assign_meth:ident}
668            {
669                $($assign_code:tt)*
670            }
671        )*
672    ) => ($(
673
674        impl $op<&$t2> for &$t1 {
675            type Output = $out;
676            #[inline]
677            $($code)*
678        }
679       
680        impl $op<$t2> for &$t1 {
681            type Output = $out;
682            #[inline]
683            fn $meth(self, mut rhs: $t2) -> $out {
684                rhs.$meth_from(self);
685                rhs
686            }
687        }
688
689        impl $op<&$t2> for $t1 {
690            type Output = $out;
691            #[inline]
692            fn $meth(mut self, rhs: &$t2) -> $out {
693                self.$meth_assign(rhs);
694                self
695            }
696        }
697
698        impl $op<$t2> for $t1 {
699            type Output = $out;
700            #[inline]
701            fn $meth(mut self, rhs: $t2) -> $out {
702                self.$meth_assign(&rhs);
703                self
704            }
705        }
706
707        impl_binop! {@op_assign
708            $t1, $t2, $out
709            $op_assign {$meth_assign}
710            {
711                $($code_assign)*
712            }
713        }
714
715        impl_binop! {@op_from
716            $t1, $t2, $out
717            $op_from {$meth_from}
718            {
719                $($code_from)*
720            }
721        }
722
723        impl_binop! {@assign_op
724            $t1, $t2, $out
725            $assign_op {$assign_meth}
726            {
727                $($assign_code)*
728            }
729        }
730    )*);
731    (
732        // a + b = a
733        op_assign
734        $t1:ident, $t2:ident, $out:ident
735        $(
736            $op:ident {$meth:ident}
737            {
738                $($code:tt)*
739            }
740            $op_assign:ident {$meth_assign:ident}
741            {
742                $($code_assign:tt)*
743            }
744            $assign_op:ident {$assign_meth:ident}
745            {
746                $($assign_code:tt)*
747            }
748        )*
749    ) => ($(
750
751        impl $op<&$t2> for &$t1 {
752            type Output = $out;
753            #[inline]
754            $($code)*
755        }
756
757        impl $op<$t2> for &$t1 {
758            type Output = $out;
759            #[inline]
760            fn $meth(self, rhs: $t2) -> $out {
761                self.$meth(&rhs)
762            }
763        }
764
765        impl $op<&$t2> for $t1 {
766            type Output = $out;
767            #[inline]
768            fn $meth(mut self, rhs: &$t2) -> $out {
769                self.$meth_assign(rhs);
770                self
771            }
772        }
773
774        impl $op<$t2> for $t1 {
775            type Output = $out;
776            #[inline]
777            fn $meth(mut self, rhs: $t2) -> $out {
778                self.$meth_assign(&rhs);
779                self
780            }
781        }
782
783        impl_binop! {@op_assign
784            $t1, $t2, $out
785            $op_assign {$meth_assign}
786            {
787                $($code_assign)*
788            }
789        }
790
791        impl_binop! {@assign_op
792            $t1, $t2, $out
793            $assign_op {$assign_meth}
794            {
795                $($assign_code)*
796            }
797        }
798    )*);
799    (
800        // a + b = b
801        op_from
802        $t1:ident, $t2:ident, $out:ident
803        $(
804            $op:ident {$meth:ident}
805            {
806                $($code:tt)*
807            }
808            $op_from:ident {$meth_from:ident}
809            {
810                $($code_from:tt)*
811            }
812            $assign_op:ident {$assign_meth:ident}
813            {
814                $($assign_code:tt)*
815            }
816        )*
817    ) => ($(
818
819        impl $op<&$t2> for &$t1 {
820            type Output = $out;
821            #[inline]
822            $($code)*
823        }
824
825        impl $op<$t2> for &$t1 {
826            type Output = $out;
827            #[inline]
828            fn $meth(self, mut rhs: $t2) -> $out {
829                rhs.$meth_from(self);
830                rhs
831            }
832        }
833
834        impl $op<&$t2> for $t1 {
835            type Output = $out;
836            #[inline]
837            fn $meth(self, rhs: &$t2) -> $out {
838                (&self).$meth(rhs)
839            }
840        }
841
842        impl $op<$t2> for $t1 {
843            type Output = $out;
844            #[inline]
845            fn $meth(self, mut rhs: $t2) -> $out {
846                rhs.$meth_from(self);
847                rhs
848            }
849        }
850
851        impl_binop! {@op_from
852            $t1, $t2, $out
853            $op_from {$meth_from}
854            {
855                $($code_from)*
856            }
857        }
858        impl_binop! {@assign_op
859            $t1, $t2, $out
860            $assign_op {$assign_meth}
861            {
862                $($assign_code)*
863            }
864        }
865    )*);
866    (
867        // a + b = c
868        $t1:ident, $t2:ident, $out:ident
869        $(
870            $op:ident {$meth:ident}
871            {
872                $($code:tt)*
873            }
874            $assign_op:ident {$assign_meth:ident}
875            {
876                $($assign_code:tt)*
877            }
878        )*
879    ) => ($(
880        impl $op<&$t2> for &$t1 {
881            type Output = $out;
882            #[inline]
883            $($code)*
884        }
885
886        impl $op<$t2> for &$t1 {
887            type Output = $out;
888            #[inline]
889            fn $meth(self, rhs: $t2) -> $out {
890                self.$meth(&rhs)
891            }
892        }
893
894        impl $op<&$t2> for $t1 {
895            type Output = $out;
896            #[inline]
897            fn $meth(self, rhs: &$t2) -> $out {
898                (&self).$meth(rhs)
899            }
900        }
901
902        impl $op<$t2> for $t1 {
903            type Output = $out;
904            #[inline]
905            fn $meth(self, rhs: $t2) -> $out {
906                (&self).$meth(&rhs)
907            }
908        }
909
910        impl_binop! {@assign_op
911            $t1, $t2, $out
912            $assign_op {$assign_meth}
913            {
914                $($assign_code)*
915            }
916        }
917    )*);
918    (
919        @op_assign
920        $t1:ident, $t2:ident, $out:ident
921        $op_assign:ident {$meth_assign:ident}
922        {
923            $($code_assign:tt)*
924        }
925    ) => {
926        impl $op_assign<&$t2> for $t1 {
927            #[inline]
928            $($code_assign)*
929        }
930
931        impl $op_assign<$t2> for $t1 {
932            #[inline]
933            fn $meth_assign(&mut self, rhs: $t2) {
934                self.$meth_assign(&rhs);
935            }
936        }
937    };
938    (
939        @op_from
940        $t1:ident, $t2:ident, $out:ident
941        $op_from:ident {$meth_from:ident}
942        {
943            $($code_from:tt)*
944        }
945    ) => {
946        impl $op_from<&$t1> for $t2 {
947            #[inline]
948            $($code_from)*
949        }
950
951        impl $op_from<$t1> for $t2 {
952            #[inline]
953            fn $meth_from(&mut self, lhs: $t1) {
954                self.$meth_from(&lhs);
955            }
956        }
957    };
958    (
959        @assign_op
960        $t1:ident, $t2:ident, $out:ident
961        $assign_op:ident {$assign_meth:ident}
962        {
963            $($assign_code:tt)*
964        }
965    ) => {
966        impl $assign_op<&$t1, &$t2> for $out {
967            #[inline]
968            $($assign_code)*
969        }
970
971        impl $assign_op<$t1, &$t2> for $out {
972            #[inline]
973            fn $assign_meth(&mut self, lhs: $t1, rhs: &$t2) {
974                self.$assign_meth(&lhs, rhs);
975            }
976        }
977
978        impl $assign_op<&$t1, $t2> for $out {
979            #[inline]
980            fn $assign_meth(&mut self, lhs: &$t1, rhs: $t2) {
981                self.$assign_meth(lhs, &rhs);
982            }
983        }
984
985        impl $assign_op<$t1, $t2> for $out {
986            #[inline]
987            fn $assign_meth(&mut self, lhs: $t1, rhs: $t2) {
988                self.$assign_meth(&lhs, &rhs);
989            }
990        }
991    };
992}
993
994/// Macros for overloading binary operators with unsafe functions.
995macro_rules! impl_binop_unsafe {
996    (
997        // a + a = a
998        $kw:ident
999        $t1:ident, $t2:ident, $out:ident
1000        $(
1001            $op:ident {$meth:ident}
1002            $op_assign:ident {$meth_assign:ident}
1003            $op_from:ident {$meth_from:ident}
1004            $assign_op:ident {$assign_meth:ident}
1005            $func:path;
1006        )+
1007    ) => ($(
1008        impl_binop! {
1009            $t1, $t2, $out
1010            $op {$meth}
1011            {
1012                fn $meth(self, rhs: &$t2) -> $out {
1013                    op_guard!($op, $kw, $out, self, rhs);
1014                    let mut res = default!($op, $kw, $out, self, rhs);
1015                    call_unsafe!($kw, $func, res, self, rhs);
1016                    res
1017                }
1018            }
1019            $op_assign {$meth_assign}
1020            {
1021                fn $meth_assign(&mut self, rhs: &$t2) {
1022                    op_guard!($op, $kw, $out, self, rhs);
1023                    call_unsafe!($kw, $func, self, self, rhs);
1024                }
1025            }
1026            $op_from {$meth_from}
1027            {
1028                fn $meth_from(&mut self, lhs: &$t2) {
1029                    op_guard!($op, $kw, $out, lhs, self);
1030                    call_unsafe!($kw, $func, self, lhs, self);
1031                }
1032            }
1033            $assign_op {$assign_meth}
1034            {
1035                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1036                    op_guard!($op, $kw, $out, lhs, rhs);
1037                    call_unsafe!($kw, $func, self, lhs, rhs);
1038                }
1039            }
1040        }
1041    )+);
1042    (
1043        // a + b = a
1044        $kw:ident
1045        op_assign
1046        $t1:ident, $t2:ident, $out:ident
1047        $(
1048            $op:ident {$meth:ident}
1049            $op_assign:ident {$meth_assign:ident}
1050            $assign_op:ident {$assign_meth:ident}
1051            $func:path;
1052        )+
1053    ) => ($(
1054        impl_binop! {
1055            op_assign
1056            $t1, $t2, $out
1057            $op {$meth}
1058            {
1059                fn $meth(self, rhs: &$t2) -> $out {
1060                    let mut res = default!($op, $kw, $out, self, rhs);
1061                    call_unsafe!($kw, $func, res, self, rhs);
1062                    res
1063                }
1064            }
1065            $op_assign {$meth_assign}
1066            {
1067                fn $meth_assign(&mut self, rhs: &$t2) {
1068                    call_unsafe!($kw, $func, self, self, rhs);
1069                }
1070            }
1071            $assign_op {$assign_meth}
1072            {
1073                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1074                    call_unsafe!($kw, $func, self, lhs, rhs);
1075                }
1076            }
1077        }
1078    )+);
1079    (
1080        // a + b = a, b primitive
1081        $kw:ident
1082        op_assign
1083        $t1:ident, $cast:ty {$($t2:ident)+}, $out:ident
1084
1085        $op:ident {$meth:ident}
1086        $op_assign:ident {$meth_assign:ident}
1087        $assign_op:ident {$assign_meth:ident}
1088        $func:path;
1089
1090        $($next:tt)*
1091    ) => ($(
1092        impl_binop_unsafe! {@inner
1093            $kw
1094            op_assign
1095            $t1, $cast {$t2}, $out
1096
1097            $op {$meth}
1098            $op_assign {$meth_assign}
1099            $assign_op {$assign_meth}
1100            $func;
1101        })+
1102
1103        impl_binop_unsafe! {
1104            $kw
1105            op_assign
1106            $t1, $cast {$($t2)+}, $out
1107            $($next)*
1108        }
1109    );
1110    (@inner
1111        $kw:ident
1112        op_assign
1113        $t1:ident, $cast:ty {$t2:ident}, $out:ident
1114        $(
1115            $op:ident {$meth:ident}
1116            $op_assign:ident {$meth_assign:ident}
1117            $assign_op:ident {$assign_meth:ident}
1118            $func:path;
1119        )*
1120    ) => ($(
1121        impl_binop! {
1122            op_assign
1123            $t1, $t2, $out
1124            $op {$meth}
1125            {
1126                fn $meth(self, rhs: &$t2) -> $out {
1127                    let mut res = default!($op, $kw, $out, self, rhs);
1128                    call_unsafe!(cast_rhs $kw, $func, $cast, res, self, rhs);
1129                    res
1130                }
1131            }
1132            $op_assign {$meth_assign}
1133            {
1134                fn $meth_assign(&mut self, rhs: &$t2) {
1135                    call_unsafe!(cast_rhs $kw, $func, $cast, self, self, rhs);
1136                }
1137            }
1138            $assign_op {$assign_meth}
1139            {
1140                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1141                    call_unsafe!(cast_rhs $kw, $func, $cast, self, lhs, rhs);
1142                }
1143            }
1144        }
1145    )*);
1146    (
1147        $kw:ident
1148        op_assign
1149        $t1:ident, $cast:ty {$($t2:ident)+}, $out:ident
1150    ) => {};
1151    (
1152        // a + b = b
1153        $kw:ident
1154        op_from
1155        $t1:ident, $t2:ident, $out:ident
1156        $(
1157            $op:ident {$meth:ident}
1158            $op_from:ident {$meth_from:ident}
1159            $assign_op:ident {$assign_meth:ident}
1160            $func:path;
1161        )+
1162    ) => ($(
1163        impl_binop! {
1164            op_from
1165            $t1, $t2, $out
1166            $op {$meth}
1167            {
1168                fn $meth(self, rhs: &$t2) -> $out {
1169                    let mut res = default!($op, $kw, $out, self, rhs);
1170                    call_unsafe!($kw, $func, res, self, rhs);
1171                    res
1172                }
1173            }
1174            $op_from {$meth_from}
1175            {
1176                fn $meth_from(&mut self, lhs: &$t1) {
1177                    call_unsafe!($kw, $func, self, lhs, self);
1178                }
1179            }
1180            $assign_op {$assign_meth}
1181            {
1182                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1183                    call_unsafe!($kw, $func, self, lhs, rhs);
1184                }
1185            }
1186        }
1187    )+);
1188    (
1189        // a + b = b, a primitive
1190        $kw:ident
1191        op_from
1192        $cast:ty {$($t1:ident)+}, $t2:ident, $out:ident
1193
1194        $op:ident {$meth:ident}
1195        $op_from:ident {$meth_from:ident}
1196        $assign_op:ident {$assign_meth:ident}
1197        $func:path;
1198
1199        $($next:tt)*
1200    ) => ($(
1201        impl_binop_unsafe! {@inner
1202            $kw
1203            op_from
1204            $cast {$t1}, $t2, $out
1205
1206            $op {$meth}
1207            $op_from {$meth_from}
1208            $assign_op {$assign_meth}
1209            $func;
1210        })+
1211
1212        impl_binop_unsafe! {
1213            $kw
1214            op_from
1215            $cast {$($t1)+}, $t2, $out
1216            $($next)*
1217        }
1218    );
1219    (@inner
1220        $kw:ident
1221        op_from
1222        $cast:ty {$t1:ident}, $t2:ident, $out:ident
1223        $(
1224            $op:ident {$meth:ident}
1225            $op_from:ident {$meth_from:ident}
1226            $assign_op:ident {$assign_meth:ident}
1227            $func:path;
1228        )*
1229    ) => ($(
1230        impl_binop! {
1231            op_from
1232            $t1, $t2, $out
1233            $op {$meth}
1234            {
1235                fn $meth(self, rhs: &$t2) -> $out {
1236                    let mut res = default!($op, $kw, $out, self, rhs);
1237                    call_unsafe!(cast_lhs $kw, $func, $cast, res, self, rhs);
1238                    res
1239                }
1240            }
1241            $op_from {$meth_from}
1242            {
1243                fn $meth_from(&mut self, lhs: &$t1) {
1244                    call_unsafe!(cast_lhs $kw, $func, $cast, self, lhs, self);
1245                }
1246            }
1247            $assign_op {$assign_meth}
1248            {
1249                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1250                    call_unsafe!(cast_lhs $kw, $func, $cast, self, lhs, rhs);
1251                }
1252            }
1253        }
1254    )*);
1255    (
1256        $kw:ident
1257        op_from
1258        $cast:ty {$($t1:ident)+}, $t2:ident, $out:ident
1259    ) => {};
1260    (
1261        // a + b = c
1262        $kw:ident
1263        $t1:ident, $t2:ident, $out:ident
1264        $(
1265            $op:ident {$meth:ident}
1266            $assign_op:ident {$assign_meth:ident}
1267            $func:path;
1268        )+
1269    ) => ($(
1270        impl_binop! {
1271            $t1, $t2, $out
1272            $op {$meth}
1273            {
1274                fn $meth(self, rhs: &$t2) -> $out {
1275                    let mut res = default!($op, $kw, $out, self, rhs);
1276                    call_unsafe!($kw, $func, res, self, rhs);
1277                    res
1278                }
1279            }
1280            $assign_op {$assign_meth}
1281            {
1282                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1283                    call_unsafe!($kw, $func, self, lhs, rhs);
1284                }
1285            }
1286        }
1287    )+);
1288    (
1289        // a + b = c, a primitive
1290        $kw:ident
1291        $cast:ty {$($t1:ident)+}, $t2:ident, $out:ident
1292
1293        $op:ident {$meth:ident}
1294        $assign_op:ident {$assign_meth:ident}
1295        $func:path;
1296
1297        $($next:tt)*
1298    ) => ($(
1299        impl_binop_unsafe! {@inner
1300            $kw
1301            $cast {$t1}, $t2, $out
1302
1303            $op {$meth}
1304            $assign_op {$assign_meth}
1305            $func;
1306        })+
1307
1308        impl_binop_unsafe! {
1309            $kw
1310            $cast {$($t1)+}, $t2, $out
1311            $($next)*
1312        }
1313    );
1314    (@inner
1315        $kw:ident
1316        $cast:ty {$t1:ident}, $t2:ident, $out:ident
1317        $(
1318            $op:ident {$meth:ident}
1319            $assign_op:ident {$assign_meth:ident}
1320            $func:path;
1321        )*
1322    ) => ($(
1323        impl_binop! {
1324            $t1, $t2, $out
1325            $op {$meth}
1326            {
1327                fn $meth(self, rhs: &$t2) -> $out {
1328                    let mut res = default!($op, $kw, $out, self, rhs);
1329                    call_unsafe!(cast_lhs $kw, $func, $cast, res, self, rhs);
1330                    res
1331                }
1332            }
1333            $assign_op {$assign_meth}
1334            {
1335                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1336                    call_unsafe!(cast_lhs $kw, $func, $cast, self, lhs, rhs);
1337                }
1338            }
1339        }
1340    )*);
1341    (
1342        $kw:ident
1343        $cast:ty {$($t1:ident)+}, $t2:ident, $out:ident
1344    ) => {};
1345    (
1346        // a + b = c, b primitive
1347        $kw:ident
1348        $t1:ident, $cast:ty {$($t2:ident)+}, $out:ident
1349
1350        $op:ident {$meth:ident}
1351        $assign_op:ident {$assign_meth:ident}
1352        $func:path;
1353
1354        $($next:tt)*
1355    ) => ($(
1356        impl_binop_unsafe! {@inner
1357            $kw
1358            $t1, $cast {$t2}, $out
1359
1360            $op {$meth}
1361            $assign_op {$assign_meth}
1362            $func;
1363        })+
1364
1365        impl_binop_unsafe! {
1366            $kw
1367            $t1, $cast {$($t2)+}, $out
1368            $($next)*
1369        }
1370    );
1371    (@inner
1372        $kw:ident
1373        $t1:ident, $cast:ty {$t2:ident}, $out:ident
1374        $(
1375            $op:ident {$meth:ident}
1376            $assign_op:ident {$assign_meth:ident}
1377            $func:path;
1378        )*
1379    ) => ($(
1380        impl_binop! {
1381            $t1, $t2, $out
1382            $op {$meth}
1383            {
1384                fn $meth(self, rhs: &$t2) -> $out {
1385                    let mut res = default!($op, $kw, $out, self, rhs);
1386                    call_unsafe!(cast_rhs $kw, $func, $cast, res, self, rhs);
1387                    res
1388                }
1389            }
1390            $assign_op {$assign_meth}
1391            {
1392                fn $assign_meth(&mut self, lhs: &$t1, rhs: &$t2) {
1393                    call_unsafe!(cast_rhs $kw, $func, $cast, self, lhs, rhs);
1394                }
1395            }
1396        }
1397    )*);
1398    (
1399        $kw:ident
1400        $t1:ident, $cast:ty {$($t2:ident)+}, $out:ident
1401    ) => {};
1402}
1403
1404/// Macros for implementing `From` for conversions.
1405#[macro_export]
1406macro_rules! impl_from {
1407    (
1408        $t1:ident, $t2:ident
1409        {
1410            $($code:tt)*
1411        }
1412    ) => {
1413        impl From<$t2> for $t1 {
1414            #[inline]
1415            fn from(src: $t2) -> $t1 {
1416                <$t1>::from(&src)
1417            }
1418        }
1419
1420        impl From<&$t2> for $t1 {
1421            #[inline]
1422            $($code)*
1423        }
1424    };
1425}
1426
1427/// Macros for implementing `From` for conversions with unsafe functions.
1428macro_rules! impl_from_unsafe {
1429    (
1430        $kw:ident
1431        $t1:ident, $t2:ident
1432        $func:path
1433    ) => (
1434        impl_from! {
1435            $t1, $t2
1436            {
1437                fn from(src: &$t2) -> $t1 {
1438                    let mut res = default!(From, $kw, $t1, src);
1439                    call_unsafe!($kw, $func, res, src);
1440                    res
1441                }
1442            }
1443        }
1444    );
1445    (
1446        // a -> b, a primitive
1447        $kw:ident
1448        $t1:ident, $cast:ident {$($t2:ident)*}
1449        $func:path
1450    ) => ($(
1451        impl_from! {
1452            $t1, $t2
1453            {
1454                fn from(src: &$t2) -> $t1 {
1455                    let mut res = default!(From, $kw, $t1, src);
1456                    call_unsafe!(cast $kw, $func, $cast, res, src);
1457                    res
1458                }
1459            }
1460        }
1461    )*);
1462    /*
1463    (
1464        // a -> b, with third argument (precision, etc)
1465        $kw:ident
1466        $t1:ident, $t2:ident, $arg:expr;
1467        $func:path
1468    ) => (
1469        impl_from! {
1470            $t1, $t2
1471            {
1472                fn from(src: &$t2) -> $t1 {
1473                    let mut res = default!(From, $kw, $t1, src);
1474                    unsafe { $func(res.as_mut_ptr(), src.as_ptr(), $arg); }
1475                    res
1476                }
1477            }
1478        }
1479    );
1480    */
1481}
1482
1483/// Macros for implementing `TryFrom` for conversions.
1484#[macro_export]
1485macro_rules! impl_tryfrom {
1486    (
1487        $t1:ident, $t2:ident
1488        {
1489            $($code:tt)*
1490        }
1491    ) => {
1492        impl TryFrom<$t2> for $t1 {
1493            type Error = &'static str;
1494            #[inline]
1495            fn try_from(src: $t2) -> Result<Self,Self::Error> {
1496                <$t1>::try_from(&src)
1497            }
1498        }
1499
1500        impl TryFrom<&$t2> for $t1 {
1501            type Error = &'static str;
1502            #[inline]
1503            $($code)*
1504        }
1505    };
1506}
1507
1508/// Macros for implementing `From` for conversions with unsafe functions.
1509macro_rules! impl_tryfrom_unsafe {
1510    (
1511        $kw:ident
1512        $t1:ident, $t2:ident
1513        $func:path
1514    ) => (
1515        impl_tryfrom! {
1516            $t1, $t2
1517            {
1518                fn from(src: &$t2) -> $t1 {
1519                    let mut res = default!(From, $kw, $t1, src);
1520                    call_unsafe!($kw, $func, res, src);
1521                    res
1522                }
1523            }
1524        }
1525    );
1526    (
1527        // a -> b, a primitive
1528        $kw:ident
1529        $t1:ident, $cast:ident {$($t2:ident)*}
1530        $func:path
1531    ) => ($(
1532        impl_tryfrom! {
1533            $t1, $t2
1534            {
1535                fn from(src: &$t2) -> $t1 {
1536                    let mut res = default!(From, $kw, $t1, src);
1537                    call_unsafe!(cast $kw, $func, $cast, res, src);
1538                    res
1539                }
1540            }
1541        }
1542    )*);
1543}
1544
1545/// Macros for implementing `Assign` for in-place assignment.
1546#[macro_export]
1547macro_rules! impl_assign {
1548    (
1549        $t1:ident, $t2:ident
1550        {
1551            $($code:tt)*
1552        }
1553    ) => {
1554        impl Assign<$t2> for $t1 {
1555            #[inline]
1556            fn assign(&mut self, src: $t2) {
1557                self.assign(&src);
1558            }
1559        }
1560
1561        impl Assign<&$t2> for $t1 {
1562            #[inline]
1563            $($code)*
1564        }
1565    };
1566}
1567
1568macro_rules! impl_assign_unsafe {
1569    (
1570        $kw:ident
1571        $t1:ident, $t2:ident
1572        $func:path
1573    ) => (
1574        impl_assign! {
1575            $t1, $t2
1576            {
1577                fn assign(&mut self, src: &$t2) {
1578                    call_unsafe!($kw, $func, self, src);
1579                }
1580            }
1581        }
1582    );
1583    (
1584        // a -> b, a primitive
1585        $kw:ident
1586        $t1:ident, $cast:ident {$($t2:ident)*}
1587        $func:path
1588    ) => ($(
1589        impl_assign! {
1590            $t1, $t2
1591            {
1592                fn assign(&mut self, src: &$t2) {
1593                    call_unsafe!(cast $kw, $func, $cast, self, src);
1594                }
1595            }
1596        }
1597    )*);
1598}
1599