7 releases
0.4.3 | Aug 2, 2024 |
---|---|
0.4.3-pre0 | Jul 19, 2024 |
0.4.0-pre2 | Jun 9, 2024 |
0.3.1 | Jun 6, 2024 |
0.1.0 |
|
#1360 in Rust patterns
672 downloads per month
81KB
1K
SLoC
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:
- Create an (unsafe) type
OptionSexp
, since there is no guarateen makesMISSING(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, - unify the two entry with lib*.so and *.so in the macro: create both.
- You should import with
use rmin::{*, println};
in std mode, otherwise an warning is generated. Sincestd::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
The v0.3.0 character
binding moves to Rchar
, since R tells me the returned 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:
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
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
.
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:
-
- currently, new method and from (rust type) method goes to SExt, you could still write
Owned<T>
::
new
()
, but aProtected<T>
yields.
- currently, new method and from (rust type) method goes to SExt, you could still write
-
- Add a
catch_unwind
forno_std
.
- Add a
-
- Move
SEXP<T>
toSexp<T>
thus SEXP and Sexp could be occur in the same situation
- Move
-
- Using macro 2.0 to hide most of the struct and method from user interface, but remains the doc for debug purpose.
-
- Adding support for lists (partially done.)
grammar
#![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
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.)))"