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