1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*!
# rmin - A minimal Rust lib for writting R extensions
This is a very early version, only support vector type, and thus its overhead is minimized.
Compare to the well-knowned `rextendr`, This crate although with some limitations but could provide a faster implementation, a smaller code size, and a faster compile time.
Since it is small enough, you could vendor this crate easily into your CRAN package easily.
# Status
The recent usable version is v0.4.3, DO NOT USE THE GIT VERSION
Please notice that, I am not familar with switching branches, the commit directly into the main branch is highly untrustable. Github is a repo only
# Breaking changes in v0.4.3:
- [x] Create an (unsafe) type [`OptionSexp`], since there is no guarateen makes `MISSING(a missing value)` in R returns non-zero (nor even returns, since the pointer may be invalid). This is not a choice, since with macro support, [`Sexp`] cannot missing,
- [x] unify the two entry with lib*.so and *.so in the macro: create both.
- [x] You should import with `use rmin::{*, println};` in std mode, otherwise an warning is generated. Since `std::println!` cannot output to Rgui.exe, override std::println with an explicit import is needed.
# Upcoming breaking changes in v0.4.0:
[`character`] re-bind to [`Sexp<char>`], which has [`SEXPTYPE`] binds to [`STRSXP`](Rdef::STRSXP)
The v0.3.0 [`character`] binding moves to [`Rchar`], since R tells me the returned [`CHARSXP`](Rdef::CHARSXP) type has the name
adding an extra '%s\0' to printf and rf_errorcall, which prevent formating errors
# Features
Need at least one of these feature: `cfg-if`(for no_std environment) or `std`(for normal usage).
<details>
<summary>Details:</summary>
# `panic-info-message`
Enable rust feature `panic_info_message`, will bring Rust panic messages back to R, might be useful for debugging. Enabled by default.
# `std`
Most of the rust crates are rely on `std::*`, if you want to use other crate, you should enable this feature. It takes ~1s compile the whole crate without `lto`, but if you enable `lto` for a faster executing speed, it might takes ~5s to finish compiling it.
# `core`
A counter part for `std`, currently `std` is an indicator that just yields a warning while not correctly being specific correctly. This feature controls the linking of exception handling language items, and thus cannot be ignored when enable it.
# `rmin-macros`
Import proc-macros `#[export] fn func_name(...)...{...}` and `done!(crate_name)` into [`crate::prelude`] and thus avaliable in [`crate`]::* root directly.
Notice that, macros require `rmin::reg` path to work (it is enabled automatically when choosing macros in `rmin` crate, if you enable rmin-macros as an independent dependency, you should enable `rmin::reg` manually.)
## `rmin-macros-camel-ass-wrapper`
Internal use only, define the internal name with camel-ass naming method (aka iOS naming method) to avoid name collision.
## `rmin-macros-warning`
Raise a warning with function with error (or empty) signature, for example. `fn()->Owned<character>` will yield a `warning, [[]] is omitted` since the signature is empty.
`fn(a:Sexp<f64>,)->Owned<f64>` also yields a same warning (due to the last comma)
They might harm the macro, thus raise an warning (although the 2 examples above are harmless, writting things like `(a:Sexp<f64>,,b:Sexp<f64>)` will interrupt the compile procedure.)
## `rmin-macros-verbose`
Disable by default, contains some simple information such as the exported function name, and what the finalizer generates.
# `public-all`
The most evil and dangerous feature. Better not to enable it. Most of the useful functions have a marker feature named `public-by-default-even-public-all-is-not-set`, that feature is a marker feature, do nothing but only tells you what function you could obtain from [`prelude`] module.
# `min-import`
For [`prelude`] module. Since all the [`RType`](base::s::r_type::RType) aliases could be access from [`crate::prelude::R`], this feature disable import the aliases into [`prelude`] module.
# `register-routines`
Register R routines, mainly for macros since hand writting such thing is painful.
# `cfg-if`
Enable by default since compile the exception handling functtion for `no_std` environment need `cfg-if`. If you are using `std` feature, this could be disabled.
# `public-by-default-even-public-all-is-not-set`
Dummy feature. Nothing happens if you disable it with `--no-default-feature`.
</details>
# Note
Please switch to [`prelude`] module page for a first glance, since I want to show all docs, most of the private things are documented with a `public-all` feature flag.
Please do not use them directly since most of them have a safe wrapper, and it is dangerous to use them directly.
# Usage
Version 0.1.0 provides a fastest (but ugly) way to achieve about 2x speedup on with functions. They are discarded in 0.2.* since they are really unsafe and may cause memory leak.
The currently 0.3.0 version is slightly different from 0.2.0, which rename `SEXP<T>` to [`Sexp<T>`], and (will) support things like [`Sexp`]<[`numeric_list`]>(R::numeric_list) or even an arbitrary list `Sexp<(T1,T2)>`.
Note: In the upcoming 0.4.0, all the decl_macro might be moved into a seperate crate which provide macros and proc_macros. This might only affect users with default no_std environment.
## 0.3.0, bring `#[no_std]` back!
In 0.3.0, feature `std` is optional again, which will give us a faster code generating speed.
### Changes:
1. - [x] currently, new method and from (rust type) method goes to SExt, you could still write [`Owned<T>`]`::`[`new`](crate::prelude::Owned::new)`()`, but a [`Protected<T>`](crate::base::s::Protected) yields.
2. - [x] Add a [`catch_unwind`](crate::base::no_std::unwind::catch_unwind) for `no_std`.
3. - [x] Move `SEXP<T>` to [`Sexp<T>`] thus SEXP and Sexp could be occur in the same situation
4. - [x] Using macro 2.0 to hide most of the struct and method from user interface, but remains the doc for debug purpose.
5. - [ ] Adding support for lists (partially done.)
### grammar
```no_run
#![no_std]
use rmin::{*, println};
/// Return a+b to R.
#[no_mangle]
pub extern "C" fn add_protect(a:Sexp<f64>,b:Sexp<f64>) -> Owned<f64> {
handle_panic(||{
let mut c=Owned::new(1);
c[0]=a[0]+b[0];
c.into()
})
}
#[no_mangle]
pub extern "C" fn add_noprotect(a:Sexp<f64>,b:Sexp<f64>) -> Owned<f64> {
handle_panic(||{
let mut c=Owned::new(1);
c[0]=a[0]+b[0];
c.into()
})
}
/// raise panic.
#[no_mangle]
pub extern "C" fn panic() -> Owned<f64> {
handle_panic(||{
panic!("error occurs")
})
}
/// with macro
/// macro will register this function, thus R will check whether all parameters are missing
#[export]
fn macro_will_expand_and_register_it(a:Sexp<f64>)->Owned<f64>{
let mut b=Owned::new(1);
b[0]=a.data().sum();
}
done!();// in case you're using macros, adding a done! is necessary, this done call generate the
// register routine, which will ensure the expanded code is checked.
fn main() {} // just makes compiler happy
```
The program above could be tested with test command
```bash
export LOAD="dyn.load('target/release/examples/libcompare_rmin.so');addnp=getNativeSymbolInfo('add_noprotect');addp=getNativeSymbolInfo('add_protect');panic=getNativeSymbolInfo('panic')" ; LC_ALL=C r -e "$LOAD;system.time(sapply(1:100000,function(x)tryCatch(.Call(wrap__panic),error=I)))" 2>/dev/null ; LC_ALL=C r -e "$LOAD;system.time(sapply(1:1000000,function(x).Call(addp,1.,2.)));system.time(sapply(1:1000000,function(x).Call(addp,1.,2.)))"
```
*/
extern crate panic_unwind;
use SEXPTYPE;
macro pm
pm!
/**
Prelude, the only thing you could (and should) use.
Originally, to prevent the misuse of things like putting [`Protected<T>`](crate::base::s::Protected) into a FFI interface, most of the structs are private and hided. And the crate is designed to function just with the visible prelude module.
Currently, a feature gate `public-all` is added, and thus users could see all of the docs, which helps debugging with this crate.
But, since the `public-all` feature gate is added to the base module, all the type are marked as **Available on crate feature `public-all` only**
For those who have `public-all` feature, to really checks what you could use directly, all the doc that prelude imports are inlined, and the prelude crate are marked as **Available on crate feature `always-avaliable-with-prelude-accesses` only.**
Here, `always-avaliable-with-prelude-accesses` is a dummy feature, it is enabled by default and does nothing (thus disable it makes nothing happens). The usage of that feature is that, when you see that feature,
you could use it without enable `public-all`. **(But other feature are still affected (such as `have_std` and `rmin-macros` and `register-routines`))**
Sometimes, you may obtain *private* things such as [`Protected<T>`](crate::base::s::Protected) (from a [`SExt`]`::<_>::`[`new`](SExt::new)`(_)`), that's OK, since the R ffi does not accept a [`Protected<T>`](crate::base::s::Protected),
and you cannot visit [`Protected<T>`](crate::base::s::Protected) directly without `public-all`, you could only keep that type until rust drop it automatically.
As for normal usage, it make no different to write `use rmin::*` or `use rmin::prelude::*`.
Choose your favorite one:)
# Example
## 1. use prelude
```
use rmin::prelude::*;
```
## 2. use a shorter version
```
use rmin::*;
```
*/
pub use *;