extendr_api/scalar/
macros.rs

1/// Generates an implementation of a unary operator Trait for a scalar type
2///
3/// Generates the implementation of the specified unary operator for both `Type` and
4/// `&Type`, using the logic of the provided closure to provide functionality.
5///
6/// This macro requires the following arguments:
7///
8/// * `$type`      - The Type the unary operator Trait is implemented for
9/// * `$opname`    - The Trait for which the implementation is generated
10/// * `$expr`      - A closure providing the logic for the implementation
11/// * `$docstring` - String to include as the Doc comment for the Trait implementation
12///
13/// Example Usage:
14///
15/// ```ignore
16/// gen_unop!(Rint, Neg, |lhs: i32| Some(-lhs), "Doc Comment");
17/// ```
18///
19/// The 'example usage' implements the following trait definitions:
20///
21/// - `impl Neg for Rint`
22/// - `impl Neg for &Rint`
23macro_rules! gen_unop {
24    ($type : ty, $opname : ident, $expr: expr, $docstring: expr) => {
25        // The 'example usage' expands to...
26        //
27        // impl Neg for Rint {
28        //      type Output = Rint;
29        //
30        //      /// Doc Comment
31        //      fn neg(self) -> Self::Output {
32        //          if let Some(lhs) = self.into() {
33        //              let f = |lhs: i32| Some(-lhs);
34        //              if let Some(res) = f(lhs) {
35        //                  return Rint::from(res);
36        //              }
37        //          }
38        //          Rint::na()
39        //      }
40        impl $opname for $type {
41            type Output = $type;
42
43            paste::paste! {
44                #[doc = $docstring]
45                // Note: $opname:lower lowercases the Trait name, i.e. Neg -> neg
46                fn [<$opname:lower>](self) -> Self::Output {
47                    if let Some(lhs) = self.into() {
48                        let f = $expr;
49                        if let Some(res) = f(lhs) {
50                            // Note that if res is NA, this will also be NA.
51                            return $type::from(res);
52                        }
53                    }
54                    $type::na()
55                }
56            }
57        }
58
59        // The 'example usage' expands to...
60        //
61        // impl Neg for &Rint {
62        //      type Output = Rint;
63        //
64        //      /// Doc Comment
65        //      fn neg(self) -> Self::Output {
66        //          if let Some(lhs) = (*self).into() {
67        //              let f = |lhs: i32| Some(-lhs);
68        //              if let Some(res) = f(lhs) {
69        //                  return Rint::from(res);
70        //              }
71        //          }
72        //          Rint::na()
73        //      }
74        impl $opname for &$type {
75            type Output = $type;
76
77            paste::paste! {
78                #[doc = $docstring]
79                // Note: $opname:lower lowercases the Trait name, i.e. Neg -> neg
80                fn [< $opname:lower >](self) -> Self::Output {
81                    if let Some(lhs) = (*self).into() {
82                        let f = $expr;
83                        if let Some(res) = f(lhs) {
84                            // Note that if res is NA, this will also be NA.
85                            return $type::from(res);
86                        }
87                    }
88                    $type::na()
89                }
90            }
91        }
92    };
93}
94
95/// Generates an implementation of a binary operator Trait for a scalar type
96///
97/// This macro requires the following arguments:
98///
99/// * `$type`      - The Type the binary operator Trait is implemented for
100/// * `$type_prim` - The primitive Rust scalar type that corresponds to `$type`
101/// * `$opname`    - The Trait for which the implementation is generated
102/// * `$expr`      - A closure providing the logic for the implementation
103/// * `$docstring` - String to include as the Doc comment for the Trait implementation
104///
105/// Example Usage:
106///
107/// ```ignore
108/// gen_binop!(Rint, i32, Add, |lhs: i32, rhs| lhs.checked_add(rhs), "Doc Comment");
109/// ```
110///
111/// The 'example usage' implements the following trait definitions:
112///
113/// - `impl Add<Rint> for Rint`
114/// - `impl Add<Rint> for &Rint`
115/// - `impl Add<i32> for Rint`
116/// - `impl Add<Rint> for i32`
117// TODO: binary operators for pairs `(Rtype, Type)` and `(Type, Rtype)` using references?
118macro_rules! gen_binop {
119    ($type : tt, $type_prim : tt, $opname : ident, $expr: expr, $docstring: expr) => {
120        // The 'example usage' expands to...
121        //
122        // impl Add<Rint> for Rint {
123        // type Output = Rint;
124        //     /// Doc Comment
125        //     fn add(self, rhs: Rint) -> Self::Output {
126        //         if let Some(lhs) = self.clone().into() {
127        //             if let Some(rhs) = rhs.into() {
128        //                 let f = |lhs: i32, rhs| lhs.checked_add(rhs);
129        //                 if let Some(res) = f(lhs, rhs) {
130        //                     return Rint::from(res);
131        //                 }
132        //             }
133        //         }
134        //         Rint::na()
135        //     }
136        // }
137        impl $opname<$type> for $type {
138            type Output = $type;
139
140            paste::paste! {
141                #[doc = $docstring]
142                // Note: $opname:lower lowercases the Trait name, i.e. Add -> add
143                fn [< $opname:lower >](self, rhs: $type) -> Self::Output {
144                    if let Some(lhs) = self.clone().into() {
145                        if let Some(rhs) = rhs.into() {
146                            let f = $expr;
147                            if let Some(res) = f(lhs, rhs) {
148                                // Note that if res is NA, this will also be NA.
149                                return $type::from(res);
150                            }
151                        }
152                    }
153                    $type::na()
154                }
155            }
156        }
157
158        // The 'example usage' expands to...
159        //
160        // impl Add<Rint> for &Rint {
161        //      type Output = Rint;
162        //      /// Doc Comment
163        //      fn add(self, rhs: Rint) -> Self::Output {
164        //          if let Some(lhs) = self.clone().into() {
165        //              if let Some(rhs) = rhs.into() {
166        //                  let f = |lhs:i32, rhs| lhs.checked_add(rhs);
167        //                  if let Some(res) = f(lhs, rhs) {
168        //                      return Rint::from(res);
169        //                  }
170        //              }
171        //          }
172        //          Rint::na()
173        //      }
174        // }
175        impl $opname<$type> for &$type {
176            type Output = $type;
177
178            paste::paste! {
179                #[doc = $docstring]
180                // Note: $opname:lower lowercases the Trait name, i.e. Add -> add
181                fn [< $opname:lower >](self, rhs: $type) -> Self::Output {
182                    if let Some(lhs) = self.clone().into() {
183                        if let Some(rhs) = rhs.into() {
184                            let f = $expr;
185                            if let Some(res) = f(lhs, rhs) {
186                                // Note that if res is NA, this will also be NA.
187                                return $type::from(res);
188                            }
189                        }
190                    }
191                    $type::na()
192                }
193            }
194        }
195
196        // The 'example usage' expands to...
197        //
198        // impl Add<i32> for Rint {
199        //      type Output = Rint;
200        //      /// Doc Comment
201        //      fn add(self, rhs: i32) -> Self::Output {
202        //          if let Some(lhs) = self.clone().into() {
203        //              let f = |lhs:i32, rhs| lhs.checked_add(rhs);
204        //              if let Some(res) = f(lhs, rhs) {
205        //                  return Rint::from(res);
206        //              }
207        //          }
208        //          Rint::na()
209        //      }
210        // }
211        impl $opname<$type_prim> for $type {
212            type Output = $type;
213
214            paste::paste! {
215                #[doc = $docstring]
216                // Note: $opname:lower lowercases the Trait name, i.e. Add -> add
217                fn [< $opname:lower >](self, rhs: $type_prim) -> Self::Output {
218                    if let Some(lhs) = self.clone().into() {
219                        let f = $expr;
220                        if let Some(res) = f(lhs, rhs) {
221                            // Note that if res is NA, this will also be NA.
222                            return $type::from(res);
223                        }
224                    }
225                    $type::na()
226                }
227            }
228        }
229
230        // The 'example usage' expands to...
231        //
232        // impl Add<Rint> for i32 {
233        //      type Output = Rint;
234        //      /// Doc Comment
235        //      fn add(self, rhs: Rint) -> Self::Output {
236        //          if let Some(rhs) = self.clone().into() {
237        //              let f = |lhs:i32, rhs| lhs.checked_add(rhs);
238        //              if let Some(res) = f(lhs, rhs) {
239        //                  return Rint::from(res);
240        //              }
241        //          }
242        //          Rint::na()
243        //      }
244        // }
245        impl $opname<$type> for $type_prim {
246            type Output = $type;
247
248            paste::paste! {
249                #[doc = $docstring]
250                // Note: $opname:lower lowercases the Trait name, i.e. Add -> add
251                fn [< $opname:lower >](self, rhs: $type) -> Self::Output {
252                    if let Some(rhs) = rhs.clone().into() {
253                        let f = $expr;
254                        if let Some(res) = f(self, rhs) {
255                            // Note that if res is NA, this will also be NA.
256                            return $type::from(res);
257                        }
258                    }
259                    $type::na()
260                }
261            }
262        }
263    };
264}
265
266/// Generates an implementation of a binary operate-assign Trait for a scalar type
267///
268/// This macro requires the following arguments:
269///
270/// * `$type`      - The Type the binary operate-assign Trait is implemented for
271/// * `$type_prim` - The primitive Rust scalar type that corresponds to `$type`
272/// * `$opname`    - The Trait for which the implementation is generated
273/// * `$expr`      - A closure providing the logic for the implementation
274/// * `$docstring` - String to include as the Doc comment for the Trait implementation
275///
276/// Example Usage:
277///
278/// ```ignore
279/// gen_binopassign!(Rint, i32, AddAssign, |lhs: i32, rhs| lhs.checked_add(rhs), "Doc Comment");
280/// ```
281///
282/// The 'example usage' implements the following trait definitions:
283///
284/// - `impl AddAssign<Rint> for Rint`
285/// - `impl AddAssign<Rint> for &mut Rint`
286/// - `impl AddAssign<i32> for Rint`
287/// - `impl AddAssign<i32> for &mut Rint`
288/// - `impl AddAssign<Rint> for Option<i32>`
289macro_rules! gen_binopassign {
290    ($type : ty, $type_prim : ty, $opname : ident, $expr: expr, $docstring: expr) => {
291        // The 'example usage' expands to...
292        //
293        // impl AddAssign<Rint> for Rint {
294        //      /// Doc Comment
295        //      fn add_assign(&mut self, other: Rint) {
296        //          match (self.clone().into(), other.into()) {
297        //              (Some(lhs), Some(rhs)) => {
298        //                  let f = |lhs: i32, rhs| lhs.checked_add(rhs);
299        //                  match f(lhs, rhs) {
300        //                      Some(res) => *self = Rint::from(res),
301        //                      None => *self = Rint:na(),
302        //                  }
303        //              }
304        //              _ => *self = Rint::na(),
305        //          }
306        //      }
307        // }
308        impl $opname<$type> for $type {
309            paste::paste! {
310                #[doc = $docstring]
311                // Note: $opname:snake snake cases the Trait name, i.e. AddAssign -> add_assign
312                fn [< $opname:snake >](&mut self, other: $type) {
313                    // `.clone()` is needed to convert &mut Rint -> Rint -> Option<$type_prim>
314                    match (self.clone().into(), other.into()) {
315                        (Some(lhs), Some(rhs)) => {
316                            let f = $expr;
317                            match f(lhs, rhs) {
318                                Some(res) => *self = $type::from(res),
319                                None => *self = $type::na(),
320                            }
321                        },
322                        _ => *self = $type::na(),
323                    }
324                }
325            }
326        }
327
328        // The 'example usage' expands to...
329        //
330        // impl AddAssign<Rint> for &mut Rint {
331        //      /// Doc Comment
332        //      fn add_assign(&mut self, other: Rint) {
333        //          match (self.clone().into(), other.into()) {
334        //              (Some(lhs), Some(rhs)) => {
335        //                  let f = |lhs: i32, rhs| lhs.checked_add(rhs);
336        //                  match f(lhs, rhs) {
337        //                      Some(res) => **self = Rint::from(res),
338        //                      None => **self = Rint:na(),
339        //                  }
340        //              }
341        //              _ => **self = Rint::na(),
342        //          }
343        //      }
344        // }
345        impl $opname<$type> for &mut $type {
346            paste::paste! {
347                #[doc = $docstring]
348                // Note: $opname:snake snake cases the Trait name, i.e. AddAssign -> add_assign
349                fn [< $opname:snake >](&mut self, other: $type) {
350                    // `.clone()` is needed to convert &mut &mut Rint -> Rint -> Option<$type_prim>
351                    match (self.clone().into(), other.into()) {
352                        (Some(lhs), Some(rhs)) => {
353                            let f = $expr;
354                            match f(lhs, rhs) {
355                                Some(res) => **self = $type::from(res),
356                                None => **self = $type::na(),
357                            }
358                        },
359                        _ => **self = $type::na(),
360                    }
361                }
362            }
363        }
364
365        // The 'example usage' expands to...
366        //
367        // impl AddAssign<i32> for Rint {
368        //      /// Doc Comment
369        //      fn add_assign(&mut self, other: i32) {
370        //          match self.clone().int() {
371        //              Some(lhs) => {
372        //                  let f = |lhs: i32, rhs| lhs.checked_add(rhs);
373        //                  match f(lhs, rhs) {
374        //                      Some(res) => *self = Rint::from(res),
375        //                      None => *self = Rint:na(),
376        //                  }
377        //              }
378        //              _ => *self = Rint::na(),
379        //              }
380        //          }
381        //      }
382        // }
383        impl $opname<$type_prim> for $type {
384            paste::paste! {
385                #[doc = $docstring]
386                // Note: $opname:snake snake cases the Trait name, i.e. AddAssign -> add_assign
387                fn [< $opname:snake >](&mut self, other: $type_prim) {
388                    // `.clone()` is needed to convert &mut Rint -> Rint -> Option<$type_prim>
389                    match self.clone().into() {
390                        Some(lhs) => {
391                            let f = $expr;
392                            match f(lhs, other) {
393                                Some(res) => *self = $type::from(res),
394                                None => *self = $type::na(),
395                            }
396                        }
397                        None => *self = $type::na(),
398                    }
399                }
400            }
401        }
402
403        // The 'example usage' expands to...
404        //
405        // impl AddAssign<i32> for &mut Rint {
406        //      /// Doc Comment
407        //      fn add_assign(&mut self, other: i32) {
408        //          match self.clone().int() {
409        //              Some(lhs) => {
410        //                  let f = |lhs: i32, rhs| lhs.checked_add(rhs);
411        //                  match f(lhs, rhs) {
412        //                      Some(res) => **self = Rint::from(res),
413        //                      None => **self = Rint:na(),
414        //                  }
415        //              }
416        //              _ => **self = Rint::na(),
417        //              }
418        //          }
419        //      }
420        // }
421        impl $opname<$type_prim> for &mut $type {
422            paste::paste! {
423                #[doc = $docstring]
424                // Note: $opname:snake snake cases the Trait name, i.e. AddAssign -> add_assign
425                fn [< $opname:snake >](&mut self, other: $type_prim) {
426                    // `.clone()` is needed to convert &mut &mut Rint -> Rint -> Option<$type_prim>
427                    match self.clone().into() {
428                        Some(lhs) => {
429                            let f = $expr;
430                            match f(lhs, other) {
431                                Some(res) => **self = $type::from(res),
432                                None => **self = $type::na(),
433                            }
434                        }
435                        None => **self = $type::na(),
436                    }
437                }
438            }
439        }
440
441        // The 'example usage' expands to...
442        //
443        //  impl AddAssign<Rint> for Option<i32> {
444        //      /// Doc Comment
445        //      fn add_assign(&mut self, other: Rint) {
446        //          match (*self, other.into()) {
447        //              (Some(lhs), Some(rhs)) => {
448        //                  let f = |lhs: i32, rhs| lhs.checked_add(rhs);
449        //                  *self = f(lhs, rhs);
450        //              },
451        //              _ => *self = None,
452        //          }
453        //      }
454        //  }
455        impl $opname<$type> for Option<$type_prim> {
456            paste::paste! {
457                #[doc = $docstring]
458                // Note: $opname:snake snake cases the Trait name, i.e. AddAssign -> add_assign
459                fn [< $opname:snake >](&mut self, other: $type) {
460                    match (*self, other.into()) {
461                        (Some(lhs), Some(rhs)) => {
462                            let f = $expr;
463                            let _ = (); // confuse clippy.
464                            *self = f(lhs, rhs);
465                        },
466                        _ => *self = None,
467                    }
468                }
469            }
470        }
471    };
472}
473
474/// Generates an implementation of type conversion Traits from a primitive type
475///
476/// This macro requires the following arguments:
477///
478/// * `$type`      - The Type the unary operator Trait is implemented for
479/// * `$type_prim` - The primitive Rust scalar type that corresponds to `$type`
480///
481/// Example Usage:
482///
483/// ```ignore
484/// gen_from_primitive!(Rint, i32);
485/// ```
486///
487/// The 'example usage' implements the following trait definitions:
488///
489/// - `From<i32> for Rint`
490/// - `From<Option<i32>> for Rint`
491macro_rules! gen_from_primitive {
492    ($type : tt, $type_prim : tt) => {
493        // The 'example usage' expands to...
494        //
495        // impl From<i32> for Rint {
496        //     fn from(v: i32) -> Self {
497        //         Self(v)
498        //     }
499        // }
500        impl From<$type_prim> for $type {
501            fn from(v: $type_prim) -> Self {
502                Self(v)
503            }
504        }
505
506        // Same but for references
507        impl From<&$type_prim> for $type {
508            fn from(v: &$type_prim) -> Self {
509                Self(*v)
510            }
511        }
512
513        // The 'example usage' expands to...
514        //
515        // impl From<Option<i32>> for Rint {
516        //     fn from(v: Option<i32>) -> Self {
517        //         if let Some(v) = v {
518        //             v.into()
519        //         } else {
520        //             Rint::na()
521        //         }
522        //     }
523        // }
524        impl From<Option<$type_prim>> for $type {
525            fn from(v: Option<$type_prim>) -> Self {
526                if let Some(v) = v {
527                    v.into()
528                } else {
529                    $type::na()
530                }
531            }
532        }
533
534        // Same but for references
535        impl From<Option<&$type_prim>> for $type {
536            fn from(v: Option<&$type_prim>) -> Self {
537                if let Some(v) = v {
538                    v.into()
539                } else {
540                    $type::na()
541                }
542            }
543        }
544    };
545}
546
547/// Generates an implementation of a number of Traits for the specified Type
548///
549/// This macro requires the following arguments:
550///
551/// * `$type`      - The Type the Traits are implemented for
552/// * `$type_prim` - The primitive Rust scalar type that corresponds to `$type`
553/// * `$na_check`  - Closure that provides `NA`-checking logic
554/// * `$na_val`    - The Rust-native value that translates to `NA`
555///
556/// Example Usage:
557///
558/// ```ignore
559/// gen_trait_impl!(Rint, i32, |x: &Rint| x.0 == i32::MIN, i32::MIN);
560/// ```
561///
562/// The 'example usage' implements the following trait definitions:
563///
564/// - `impl Clone for Rint`
565/// - `impl Copy for Rint`
566/// - `impl CanBeNA for Rint`             // Includes doc test
567/// - `impl Debug for Rint`
568/// - `impl PartialEq<Rint> for Rint`     // Includes doc test
569/// - `impl PartialEq<i32> for Rint`      // Includes doc test
570/// - `impl Default for Rint`             // Includes doc test
571macro_rules! gen_trait_impl {
572    ($type : ident, $type_prim : ty, $na_check : expr, $na_val : expr) => {
573        // The 'example usage' expands to...
574        //
575        // impl Clone for Rint {
576        //     fn clone(&self) -> Self {
577        //         Self(self.0)
578        //     }
579        // }
580        impl Clone for $type {
581            fn clone(&self) -> Self {
582                *self
583            }
584        }
585
586        // The 'example usage' expands to...
587        //
588        // impl Copy for Rint {}
589        impl Copy for $type {}
590
591        // The 'example usage' expands to...
592        //
593        // /// Documentation comments/test built by the #[doc] attributes
594        // impl CanBeNA for Rint {
595        //     fn is_na(&self) -> bool {
596        //         (|x: &Rint| x.0 == i32::MIN)(self)
597        //     }
598        //
599        //     fn na() -> Self {
600        //         Rint(i32::MIN)
601        //     }
602        // }
603        paste::paste! {
604            #[doc = "```"]
605            #[doc = "use extendr_api::prelude::*;"]
606            #[doc = "test! {"]
607            #[doc = "    assert!((<" $type ">::na()).is_na());"]
608            #[doc = "}"]
609            #[doc = "```"]
610            impl CanBeNA for $type {
611                /// Return true is the is a NA value.
612                fn is_na(&self) -> bool {
613                    $na_check(self)
614                }
615                /// Construct a NA.
616                fn na() -> Self {
617                    $type($na_val)
618                }
619            }
620        }
621
622        // The 'example usage' expands to...
623        //
624        //
625        // /// Documentation comments/test built by the #[doc] attributes
626        // impl PartialEq<Rint> for Rint {
627        //     fn eq(&self, other: &Rint) -> bool {
628        //         !(self.is_na() || other.is_na()) && self.0 == other.0
629        //     }
630        // }
631        paste::paste! {
632            #[doc = "```"]
633            #[doc = "use extendr_api::prelude::*;"]
634            #[doc = "test! {"]
635            #[doc = "    assert!(<" $type ">::default().eq(&<" $type ">::default()));"]
636            #[doc = "    assert!(!<" $type ">::na().eq(&<" $type ">::na()));"]
637            #[doc = "}"]
638            #[doc = "```"]
639            impl PartialEq<$type> for $type {
640                fn eq(&self, other: &$type) -> bool {
641                    !(self.is_na() || other.is_na()) && self.inner().eq(&other.inner())
642                }
643            }
644        }
645
646        paste::paste! {
647            #[doc = "```"]
648            #[doc = "use extendr_api::prelude::*;"]
649            #[doc = "test! {"]
650            #[doc = "    assert!(<" $type ">::default().eq(&<" $type_prim ">::default()));"]
651            #[doc = "}"]
652            #[doc = "```"]
653            impl PartialEq<$type_prim> for $type {
654                /// NA always fails.
655                fn eq(&self, other: &$type_prim) -> bool {
656                    <Option<$type_prim>>::try_from(self.clone()) == Ok(Some(*other))
657                }
658            }
659        }
660        paste::paste! {
661            #[doc = "```"]
662            #[doc = "use extendr_api::prelude::*;"]
663            #[doc = "test! {"]
664            #[doc = "    assert!(<" $type_prim ">::default().eq(&<" $type ">::default()));"]
665            #[doc = "}"]
666            #[doc = "```"]
667            impl PartialEq<$type> for $type_prim {
668                fn eq(&self, other: &$type) -> bool {
669                    <Option<$type_prim>>::try_from(*other) == Ok(Some(*self))
670                }
671            }
672        }
673
674        // The 'example usage' expands to...
675        //
676        // /// Documentation comments/test built by the #[doc] attributes
677        // impl std::default::Default for Rint {
678        //     fn default() -> Self {
679        //         Rint(<i32>::default())
680        //     }
681        // }
682        paste::paste! {
683            #[doc = "```"]
684            #[doc = "use extendr_api::prelude::*;"]
685            #[doc = "test! {"]
686            #[doc = "    assert_eq!(<" $type ">::default(), <" $type_prim ">::default());"]
687            #[doc = "}"]
688            #[doc = "```"]
689            impl std::default::Default for $type {
690                fn default() -> Self {
691                    $type::from(<$type_prim>::default())
692                }
693            }
694        }
695    };
696}
697
698macro_rules! gen_partial_ord {
699    ($type : ident, $type_prim : ty) => {
700        paste::paste! {
701            #[doc = "```"]
702            #[doc = "use extendr_api::prelude::*;"]
703            #[doc = "test! {"]
704            #[doc = "    assert_eq!(<" $type ">::default() <  <" $type ">::na(), false);"]
705            #[doc = "    assert_eq!(<" $type ">::default() <= <" $type ">::na(), false);"]
706            #[doc = "    assert_eq!(<" $type ">::default() >  <" $type ">::na(), false);"]
707            #[doc = "    assert_eq!(<" $type ">::default() >= <" $type ">::na(), false);"]
708            #[doc = "    assert_eq!(<" $type ">::default() <  <" $type ">::default(), false);"]
709            #[doc = "    assert_eq!(<" $type ">::default() <= <" $type ">::default(), true);"]
710            #[doc = "    assert_eq!(<" $type ">::default() >  <" $type ">::default(), false);"]
711            #[doc = "    assert_eq!(<" $type ">::default() >= <" $type ">::default(), true);"]
712            #[doc = "}"]
713            #[doc = "```"]
714            impl std::cmp::PartialOrd<$type> for $type {
715                fn partial_cmp(&self, other: &$type) -> Option<std::cmp::Ordering> {
716                    if self.is_na() || other.is_na() {
717                        None
718                    } else {
719                        self.inner().partial_cmp(&other.inner())
720                    }
721                }
722            }
723        }
724
725        paste::paste! {
726            #[doc = "```"]
727            #[doc = "use extendr_api::prelude::*;"]
728            #[doc = "test! {"]
729            #[doc = "    assert_eq!(<" $type_prim ">::default() <  <" $type ">::na(), false);"]
730            #[doc = "    assert_eq!(<" $type_prim ">::default() <= <" $type ">::na(), false);"]
731            #[doc = "    assert_eq!(<" $type_prim ">::default() >  <" $type ">::na(), false);"]
732            #[doc = "    assert_eq!(<" $type_prim ">::default() >= <" $type ">::na(), false);"]
733            #[doc = "    assert_eq!(<" $type_prim ">::default() <  <" $type ">::default(), false);"]
734            #[doc = "    assert_eq!(<" $type_prim ">::default() <= <" $type ">::default(), true);"]
735            #[doc = "    assert_eq!(<" $type_prim ">::default() >  <" $type ">::default(), false);"]
736            #[doc = "    assert_eq!(<" $type_prim ">::default() >= <" $type ">::default(), true);"]
737            #[doc = "}"]
738            #[doc = "```"]
739            impl std::cmp::PartialOrd<$type_prim> for $type {
740                fn partial_cmp(&self, other: &$type_prim) -> Option<std::cmp::Ordering> {
741                    let other: $type = (*other).try_into().unwrap_or($type::na());
742                    self.partial_cmp(&other)
743                }
744            }
745        }
746
747        paste::paste! {
748            #[doc = "```"]
749            #[doc = "use extendr_api::prelude::*;"]
750            #[doc = "test! {"]
751            #[doc = "    assert_eq!(<" $type ">::default() <  <" $type ">::default(), false);"]
752            #[doc = "    assert_eq!(<" $type ">::default() <= <" $type ">::default(), true);"]
753            #[doc = "    assert_eq!(<" $type ">::default() >  <" $type ">::default(), false);"]
754            #[doc = "    assert_eq!(<" $type ">::default() >= <" $type ">::default(), true);"]
755            #[doc = "}"]
756            #[doc = "```"]
757            impl std::cmp::PartialOrd<$type> for $type_prim {
758                fn partial_cmp(&self, other: &$type) -> Option<std::cmp::Ordering> {
759                    let slf: $type = (*self).try_into().unwrap_or($type::na());
760                    slf.partial_cmp(other)
761                }
762            }
763        }
764    };
765}
766
767/// Generates an implementation of `std::iter::Sum` for a scalar type
768///
769/// This macro requires the following argument:
770///
771/// * `$type`   - The Type to implement `std::iter::Sum` for
772///
773/// Example Usage:
774///
775/// ```ignore
776/// gen_sum_iter!(Rint);
777/// ```
778macro_rules! gen_sum_iter {
779    ($type : ty) => {
780        // The 'example usage' expands to...
781        //
782        // impl std::iter::Sum for $type {
783        //     /// Documentation comments/test built by the #[doc] attributes
784        //     fn sum<I: Iterator<Item = Rint>>(iter: I) -> Rint {
785        //         iter.fold(Rint::default(), |a, b| a + b)
786        //     }
787        // }
788        impl std::iter::Sum for $type {
789            paste::paste! {
790                #[doc = "Yields NA on overflow if NAs present."]
791                #[doc = "```"]
792                #[doc = "use extendr_api::prelude::*;"]
793                #[doc = "use std::iter::Sum;"]
794                #[doc = "test! {"]
795                #[doc = "    let x = (0..100).map(|x| " $type "::default());"]
796                #[doc = "    assert_eq!(<" $type " as Sum>::sum(x), <" $type ">::default());"]
797                #[doc = "}"]
798                #[doc = "```"]
799                fn sum<I: Iterator<Item = $type>>(iter: I) -> $type {
800                    iter.fold($type::default(), |a, b| a + b)
801                }
802            }
803        }
804
805        // The 'example usage' expands to...
806        //
807        // impl std::iter::Sum for &$type {
808        //     /// Documentation comments/test built by the #[doc] attributes
809        //     fn sum<I: Iterator<Item = &Rint>>(iter: I) -> Rint {
810        //         iter.fold(Rint::default(), |a, b| a + b)
811        //     }
812        // }
813        impl<'a> std::iter::Sum<&'a $type> for $type {
814            paste::paste! {
815                #[doc = "Yields NA on overflow if NAs present."]
816                #[doc = "```"]
817                #[doc = "use extendr_api::prelude::*;"]
818                #[doc = "use std::iter::Sum;"]
819                #[doc = "test! {"]
820                #[doc = "    let z =" $type "::default();"]
821                #[doc = "    let x = (0..100).map(|_| &z);"]
822                #[doc = "    assert_eq!(<" $type " as Sum<& " $type ">>::sum(x), <" $type ">::default());"]
823                #[doc = "}"]
824                #[doc = "```"]
825                fn sum<I: Iterator<Item = &'a $type>>(iter: I) -> $type {
826                    iter.fold($type::default(), |a, b| a + *b)
827                }
828            }
829        }
830    };
831}
832
833pub(in crate::scalar) use gen_binop;
834pub(in crate::scalar) use gen_binopassign;
835pub(in crate::scalar) use gen_from_primitive;
836pub(in crate::scalar) use gen_partial_ord;
837pub(in crate::scalar) use gen_sum_iter;
838pub(in crate::scalar) use gen_trait_impl;
839pub(in crate::scalar) use gen_unop;