extendr_api/scalar/
rint.rs

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