extendr_api/scalar/
rint.rs

1use crate::scalar::macros::*;
2use crate::*;
3use std::cmp::Ordering::*;
4use std::convert::TryFrom;
5use std::ops::{Add, Div, Mul, Neg, Not, Sub};
6use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
7
8/// `Rint` is a wrapper for `i32` in the context of an R's integer vector.
9///
10/// `Rint` can have a value between `i32::MIN+1` and `i32::MAX`
11///
12/// The value `i32::MIN` is used as `"NA"`.
13///
14/// `Rint` has the same footprint as an `i32` value allowing us to use it in zero copy slices.
15#[repr(transparent)]
16#[readonly::make]
17pub struct Rint(pub i32);
18
19impl Rint {
20    pub fn new(val: i32) -> Self {
21        Rint(val)
22    }
23
24    /// ```
25    /// use extendr_api::prelude::*;
26    /// test! {
27    ///     assert!(Rint::na().min(Rint::default()).is_na());    
28    ///     assert!(Rint::default().min(Rint::na()).is_na());
29    ///     assert_eq!(Rint::default().min(Rint::default()), Rint::default());
30    ///     assert_eq!(Rint::from(1).min(Rint::from(2)), Rint::from(1));    
31    ///     assert_eq!(Rint::from(2).min(Rint::from(1)), Rint::from(1));    
32    /// }
33    /// ```
34    pub fn min(&self, other: Self) -> Self {
35        match self.partial_cmp(&other) {
36            Some(Less | Equal) => *self,
37            Some(Greater) => other,
38            _ => Self::na(),
39        }
40    }
41
42    /// ```
43    /// use extendr_api::prelude::*;
44    /// test! {
45    ///     assert!(Rint::na().max(Rint::default()).is_na());    
46    ///     assert!(Rint::default().max(Rint::na()).is_na());
47    ///     assert_eq!(Rint::default().max(Rint::default()), Rint::default());
48    ///     assert_eq!(Rint::from(1).max(Rint::from(2)), Rint::from(2));    
49    ///     assert_eq!(Rint::from(2).max(Rint::from(1)), Rint::from(2));    
50    /// }
51    /// ```
52    pub fn max(&self, other: Self) -> Self {
53        match self.partial_cmp(&other) {
54            Some(Less) => other,
55            Some(Greater | Equal) => *self,
56            _ => Self::na(),
57        }
58    }
59}
60
61gen_trait_impl!(Rint, i32, |x: &Rint| x.0 == i32::MIN, i32::MIN);
62gen_from_primitive!(Rint, i32);
63
64impl From<Rint> for Option<i32> {
65    fn from(v: Rint) -> Self {
66        if v.is_na() {
67            None
68        } else {
69            Some(v.0)
70        }
71    }
72}
73
74gen_sum_iter!(Rint);
75gen_partial_ord!(Rint, i32);
76
77// Generate binary ops for `+`, `-`, `*` and `/`
78gen_binop!(
79    Rint,
80    i32,
81    Add,
82    |lhs: i32, rhs| lhs.checked_add(rhs),
83    "Add two Rint values or an option of i32, overflows to NA."
84);
85gen_binop!(
86    Rint,
87    i32,
88    Sub,
89    |lhs: i32, rhs| lhs.checked_sub(rhs),
90    "Subtract two Rint values or an option of i32, overflows to NA."
91);
92gen_binop!(
93    Rint,
94    i32,
95    Mul,
96    |lhs: i32, rhs| lhs.checked_mul(rhs),
97    "Multiply two Rint values or an option of i32, overflows to NA."
98);
99gen_binop!(
100    Rint,
101    i32,
102    Div,
103    |lhs: i32, rhs| lhs.checked_div(rhs),
104    "Divide two Rint values or an option of i32, overflows to NA."
105);
106gen_binopassign!(
107    Rint,
108    i32,
109    AddAssign,
110    |lhs: i32, rhs| lhs.checked_add(rhs),
111    "Add two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
112);
113gen_binopassign!(
114    Rint,
115    i32,
116    SubAssign,
117    |lhs: i32, rhs| lhs.checked_sub(rhs),
118    "Subtract two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
119);
120gen_binopassign!(
121    Rint,
122    i32,
123    MulAssign,
124    |lhs: i32, rhs| lhs.checked_mul(rhs),
125    "Multiply two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
126);
127gen_binopassign!(
128    Rint,
129    i32,
130    DivAssign,
131    |lhs: i32, rhs| lhs.checked_div(rhs),
132    "Divide two Rint values or an option of i32, modifying the left-hand side in place. Overflows to NA."
133);
134
135// Generate unary ops for -, !
136gen_unop!(
137    Rint,
138    Neg,
139    |lhs: i32| Some(-lhs),
140    "Negate a Rint value, overflows to NA."
141);
142gen_unop!(
143    Rint,
144    Not,
145    |lhs: i32| Some(!lhs),
146    "Logical not a Rint value, overflows to NA."
147);
148
149impl TryFrom<&Robj> for Rint {
150    type Error = Error;
151
152    fn try_from(robj: &Robj) -> Result<Self> {
153        let i32_val: Result<i32> = robj.try_into();
154        match i32_val {
155            Ok(v) => Ok(Rint::from(v)),
156            // TODO: Currently this results in an extra protection of robj
157            Err(Error::MustNotBeNA(_)) => Ok(Rint::na()),
158            Err(e) => Err(e),
159        }
160    }
161}
162
163impl std::fmt::Debug for Rint {
164    /// Debug format.
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        if self.is_na() {
167            write!(f, "NA_INTEGER")
168        } else {
169            self.0.fmt(f)
170        }
171    }
172}