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*/