Skip to main content

aorist_extendr_api/robj/
operators.rs

1use crate::*;
2use std::ops::{Add, Div, Mul, Sub};
3
4///////////////////////////////////////////////////////////////
5/// The following impls add operators to Robj.
6///
7impl Robj {
8    /// Do the equivalent of x$y
9    /// ```
10    /// use extendr_api::prelude::*;
11    /// test! {
12    /// let env = Environment::from_pairs(global_env(),
13    ///    vec![("a".to_string(), r!(1)), ("b".to_string(), r!(2))]);
14    /// assert_eq!(env.dollar("a").unwrap(), r!(1));
15    /// assert_eq!(env.dollar("b").unwrap(), r!(2));
16    /// }
17    /// ```
18    pub fn dollar<T>(&self, symbol: T) -> Result<Robj>
19    where
20        T: AsRef<str>,
21    {
22        let symbol: Symbol = Symbol::from_string(symbol.as_ref());
23        call!("$", self, symbol)
24    }
25
26    /// Do the equivalent of `x[y]`
27    /// ```
28    /// use extendr_api::prelude::*;
29    /// test! {
30    /// let vec = r!([10, 20, 30]);
31    /// assert_eq!(vec.slice(2).unwrap(), r!(20));
32    /// assert_eq!(vec.slice(2..=3).unwrap(), r!([20, 30]));
33    /// }
34    /// ```
35    pub fn slice<T>(&self, rhs: T) -> Result<Robj>
36    where
37        T: Into<Robj>,
38    {
39        call!("[", self, rhs.into())
40    }
41
42    /// Do the equivalent of `x[[y]]`
43    /// ```
44    /// use extendr_api::prelude::*;
45    /// test! {
46    /// let vec = r!([10, 20, 30]);
47    /// assert_eq!(vec.index(2).unwrap(), r!(20));
48    /// assert_eq!(vec.index(2..=3).is_err(), true);
49    /// }
50    /// ```
51    pub fn index<T>(&self, rhs: T) -> Result<Robj>
52    where
53        T: Into<Robj>,
54    {
55        call!("[[", self, rhs.into())
56    }
57
58    /// Do the equivalent of x ~ y
59    /// ```
60    /// use extendr_api::prelude::*;
61    /// test! {
62    ///     let x = r!(Symbol::from_string("x"));
63    ///     let y = r!(Symbol::from_string("y"));
64    ///     let tilde = x.tilde(y).unwrap();
65    ///     assert_eq!(tilde.inherits("formula"), true);
66    /// }
67    /// ```
68    pub fn tilde<T>(&self, rhs: T) -> Result<Robj>
69    where
70        T: Into<Robj>,
71    {
72        call!("~", self, rhs.into())
73    }
74
75    /// Do the equivalent of x :: y
76    /// ```
77    /// use extendr_api::prelude::*;
78    /// test! {
79    /// let base = r!(Symbol::from_string("base"));
80    /// let env = r!(Symbol::from_string(".getNamespace"));
81    /// let base_env = base.double_colon(env).unwrap();
82    /// assert_eq!(base_env.is_function(), true);
83    /// }
84    /// ```
85    pub fn double_colon<T>(&self, rhs: T) -> Result<Robj>
86    where
87        T: Into<Robj>,
88    {
89        call!("::", self, rhs.into())
90    }
91
92    /// Do the equivalent of x(a, b, c)
93    /// ```
94    /// use extendr_api::prelude::*;
95    /// test! {
96    ///     let function = R!("function(a, b) a + b").unwrap();
97    ///     assert_eq!(function.is_function(), true);
98    ///     assert_eq!(function.call(pairlist!(a=1, b=2)).unwrap(), r!(3));
99    /// }
100    /// ```
101    pub fn call(&self, args: Pairlist) -> Result<Robj> {
102        if self.rtype() != RType::Function {
103            return Err(Error::ExpectedFunction(self.clone()));
104        }
105
106        unsafe {
107            let call = new_owned(Rf_lcons(self.get(), args.get()));
108            call.eval()
109        }
110    }
111}
112
113impl<Rhs> Add<Rhs> for Robj
114where
115    Rhs: Into<Robj>,
116{
117    type Output = Robj;
118
119    /// Add two R objects, consuming the left hand side.
120    /// panics on error.
121    /// ```
122    /// use extendr_api::prelude::*;
123    /// test! {
124    ///
125    /// // lhs and rhs get dropped here
126    /// let lhs = r!([1, 2]);
127    /// let rhs = r!([10, 20]);
128    /// assert_eq!(lhs + rhs, r!([11, 22]));
129    ///
130    /// // lhs gets dropped and rhs is a temporary object.
131    /// let lhs = r!([1, 2]);
132    /// assert_eq!(lhs + 1000, r!([1001, 1002]));
133    ///
134    /// // Only lhs gets dropped.
135    /// let lhs = r!([1, 2]);
136    /// let rhs = r!([10, 20]);
137    /// assert_eq!(lhs + &rhs, r!([11, 22]));
138    /// }
139    /// ```
140    fn add(self, rhs: Rhs) -> Self::Output {
141        call!("+", self, rhs.into()).expect("Robj add failed")
142    }
143}
144
145impl<Rhs> Sub<Rhs> for Robj
146where
147    Rhs: Into<Robj>,
148{
149    type Output = Robj;
150
151    /// Subtract two R objects, consuming the left hand side.
152    /// panics on error.
153    /// ```
154    /// use extendr_api::prelude::*;
155    /// test! {
156    ///
157    /// // lhs and rhs get dropped here
158    /// let lhs = r!([10, 20]);
159    /// let rhs = r!([1, 2]);
160    /// assert_eq!(lhs - rhs, r!([9, 18]));
161    ///
162    /// // lhs gets dropped and rhs is a temporary object.
163    /// let lhs = r!([1000, 2000]);
164    /// assert_eq!(lhs - 1, r!([999, 1999]));
165    ///
166    /// // Only lhs gets dropped.
167    /// let lhs = r!([10, 20]);
168    /// let rhs = r!([1, 2]);
169    /// assert_eq!(lhs - &rhs, r!([9, 18]));
170    /// }
171    /// ```
172    fn sub(self, rhs: Rhs) -> Self::Output {
173        call!("-", self, rhs.into()).expect("Robj subtract failed")
174    }
175}
176
177impl<Rhs> Mul<Rhs> for Robj
178where
179    Rhs: Into<Robj>,
180{
181    type Output = Robj;
182
183    /// Multiply two R objects, consuming the left hand side.
184    /// panics on error.
185    /// ```
186    /// use extendr_api::prelude::*;
187    /// test! {
188    ///
189    /// // lhs and rhs get dropped here
190    /// let lhs = r!([10.0, 20.0]);
191    /// let rhs = r!([1.0, 2.0]);
192    /// assert_eq!(lhs * rhs, r!([10.0, 40.0]));
193    ///
194    /// // lhs gets dropped and rhs is a temporary object.
195    /// let lhs = r!([1.0, 2.0]);
196    /// assert_eq!(lhs * 10.0, r!([10.0, 20.0]));
197    ///
198    /// // Only lhs gets dropped.
199    /// let lhs = r!([10.0, 20.0]);
200    /// let rhs = r!([1.0, 2.0]);
201    /// assert_eq!(lhs * &rhs, r!([10.0, 40.0]));
202    /// }
203    /// ```
204    fn mul(self, rhs: Rhs) -> Self::Output {
205        call!("*", self, rhs.into()).expect("Robj multiply failed")
206    }
207}
208
209impl<Rhs> Div<Rhs> for Robj
210where
211    Rhs: Into<Robj>,
212{
213    type Output = Robj;
214
215    /// Divide two R objects, consuming the left hand side.
216    /// panics on error.
217    /// ```
218    /// use extendr_api::prelude::*;
219    /// test! {
220    ///
221    /// // lhs and rhs get dropped here
222    /// let lhs = r!([10.0, 20.0]);
223    /// let rhs = r!([1.0, 2.0]);
224    /// assert_eq!(lhs / rhs, r!([10.0, 10.0]));
225    ///
226    /// // lhs gets dropped and rhs is a temporary object.
227    /// let lhs = r!([10.0, 30.0]);
228    /// assert_eq!(lhs / 10.0, r!([1.0, 3.0]));
229    ///
230    /// // Only lhs gets dropped.
231    /// let lhs = r!([10.0, 20.0]);
232    /// let rhs = r!([1.0, 2.0]);
233    /// assert_eq!(lhs / &rhs, r!([10.0, 10.0]));
234    /// }
235    /// ```
236    fn div(self, rhs: Rhs) -> Self::Output {
237        call!("/", self, rhs.into()).expect("Robj divide failed")
238    }
239}
240
241// Calls are still experimental.
242//
243// impl<Args> Fn(Args) for Robj
244// {
245//     extern "rust-call" fn call(&self, args: Args) -> Self::Output {
246
247//     }
248// }
249
250/* list of primitives in base.
251> b[sapply(b, function(b) is.primitive(get(b, baseenv())))]
252  [1] "-"               ":"               "!"               "!="
253  [5] "("               "["               "[["              "[[<-"
254  [9] "[<-"             "{"               "@"               "@<-"
255 [13] "*"               "/"               "&"               "&&"
256 [17] "%*%"             "%/%"             "%%"              "^"
257 [21] "+"               "<"               "<-"              "<<-"
258 [25] "<="              "="               "=="              ">"
259 [29] ">="              "|"               "||"              "~"
260 [33] "$"               "$<-"             "abs"             "acos"
261 [37] "acosh"           "all"             "any"             "anyNA"
262 [41] "Arg"             "as.call"         "as.character"    "as.complex"
263 [45] "as.double"       "as.environment"  "as.integer"      "as.logical"
264 [49] "as.numeric"      "as.raw"          "asin"            "asinh"
265 [53] "atan"            "atanh"           "attr"            "attr<-"
266 [57] "attributes"      "attributes<-"    "baseenv"         "break"
267 [61] "browser"         "c"               "call"            "ceiling"
268 [65] "class"           "class<-"         "Conj"            "cos"
269 [69] "cosh"            "cospi"           "cummax"          "cummin"
270 [73] "cumprod"         "cumsum"          "digamma"         "dim"
271 [77] "dim<-"           "dimnames"        "dimnames<-"      "emptyenv"
272 [81] "enc2native"      "enc2utf8"        "environment<-"   "exp"
273 [85] "expm1"           "expression"      "floor"           "for"
274 [89] "forceAndCall"    "function"        "gamma"           "gc.time"
275 [93] "globalenv"       "if"              "Im"              "interactive"
276 [97] "invisible"       "is.array"        "is.atomic"       "is.call"
277[101] "is.character"    "is.complex"      "is.double"       "is.environment"
278[105] "is.expression"   "is.finite"       "is.function"     "is.infinite"
279[109] "is.integer"      "is.language"     "is.list"         "is.logical"
280[113] "is.matrix"       "is.na"           "is.name"         "is.nan"
281[117] "is.null"         "is.numeric"      "is.object"       "is.pairlist"
282[121] "is.raw"          "is.recursive"    "is.single"       "is.symbol"
283[125] "isS4"            "lazyLoadDBfetch" "length"          "length<-"
284[129] "levels<-"        "lgamma"          "list"            "log"
285[133] "log10"           "log1p"           "log2"            "max"
286[137] "min"             "missing"         "Mod"             "names"
287[141] "names<-"         "nargs"           "next"            "nzchar"
288[145] "oldClass"        "oldClass<-"      "on.exit"         "pos.to.env"
289[149] "proc.time"       "prod"            "quote"           "range"
290[153] "Re"              "rep"             "repeat"          "retracemem"
291[157] "return"          "round"           "seq_along"       "seq_len"
292[161] "seq.int"         "sign"            "signif"          "sin"
293[165] "sinh"            "sinpi"           "sqrt"            "standardGeneric"
294[169] "storage.mode<-"  "substitute"      "sum"             "switch"
295[173] "tan"             "tanh"            "tanpi"           "tracemem"
296[177] "trigamma"        "trunc"           "unclass"         "untracemem"
297[181] "UseMethod"       "while"           "xtfrm"
298*/