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;