#extension #lib #writting

nightly no-std rmin

一个用于编写 R 扩展的最小化 Rust 库

7 个版本

0.4.3 2024 年 8 月 2 日
0.4.3-pre02024 年 7 月 19 日
0.4.0-pre22024 年 6 月 9 日
0.3.1 2024 年 6 月 6 日
0.1.0 2024 年 5 月 31 日

#1 in #writting

Download history 99/week @ 2024-05-25 305/week @ 2024-06-01 83/week @ 2024-06-08 11/week @ 2024-06-15 114/week @ 2024-07-06 69/week @ 2024-07-13 30/week @ 2024-07-20 100/week @ 2024-07-27 27/week @ 2024-08-03

230 个月下载量

AGPL-3.0

81KB
1K SLoC

rmin - 一个用于编写 R 扩展的最小化 Rust 库

这是一个非常早期的版本,仅支持向量类型,因此其开销最小化。

与广为人知的 rextendr 相比,这个包尽管有一些限制,但可以提供更快的实现、更小的代码大小和更快的编译时间。

由于它足够小,你可以很容易地将这个包集成到你的 CRAN 软件包中。

状态

最近可用的版本是 v0.4.3,不要使用 GIT 版本

请注意,我对切换分支不熟悉,直接提交到主分支是非常不可信的。GitHub 只是一个仓库

v0.4.3 版本中的破坏性变化

  • 创建一个(不安全的)类型 OptionSexp,因为 R 中的 MISSING(一个缺失值) 返回非零(甚至不返回,因为指针可能无效)。这不是选择,因为有了宏支持,Sexp 不能缺失,
  • 在宏中统一两个入口与 lib*.so 和 *.so:创建两者。
  • 你应该使用 use rmin::{*, println}; 在 std 模式下导入,否则会生成警告。因为 std::println! 不能输出到 Rgui.exe,需要显式导入来覆盖 std::println。

v0.4.0 版本即将到来的破坏性变化

character 重新绑定到 Sexp<char>,它将 SEXPTYPE 绑定到 STRSXP

版本0.3.0的character绑定移动到Rchar,因为R告诉我返回的CHARSXP类型名称为

在printf和rf_errorcall中添加额外的'%s\0',以防止格式化错误

特性

需要以下特性之一:cfg-if(用于无_std环境)或std(用于常规使用)。

详细信息

panic-info-message

启用Rust特性panic_info_message,将Rust的panic消息返回到R,可能对调试很有用。默认启用。

std

大多数Rust包都依赖于std::*,如果你想要使用其他包,应该启用此特性。不使用lto编译整个包大约需要1秒,但如果为了更快的执行速度启用lto,可能需要大约5秒来完成编译。

core

std的对应特性,目前std只是一个发出警告而未正确具体化的指示器。此特性控制异常处理语言项的链接,因此启用时不能忽略。

rmin-macros

将进程宏#[export] fn func_name(...)...{...}done!(crate_name)导入到crate::prelude,因此在crate::*根目录下直接可用。

请注意,宏需要rmin::reg路径才能工作(在rmin包中选择宏时自动启用,如果你将rmin-macros作为独立的依赖项启用,你应该手动启用rmin::reg)。

rmin-macros-camel-ass-wrapper

仅限内部使用,使用驼峰命名法(即iOS命名法)定义内部名称,以避免名称冲突。

rmin-macros-warning

对于具有错误(或空)签名的函数发出警告,例如。例如,fn()->Owned<character>将产生一个警告warning, [[]] is omitted,因为签名是空的。

fn(a:Sexp<f64>,)->Owned<f64> 同样会引发相同的警告(由于最后一个逗号)

它们可能会损害宏,从而引发警告(尽管上面两个例子是无害的,但像 (a:Sexp<f64>,,b:Sexp<f64>) 这样的写法将中断编译过程。)

rmin-macros-verbose

默认禁用,包含一些简单信息,例如导出的函数名称和终结器生成的内容。

public-all

最邪恶且危险的功能。最好不要启用它。大多数有用的函数都有一个名为 public-by-default-even-public-all-is-not-set 的标记功能,该功能是一个标记功能,不做任何事情,只是告诉你可以从 prelude 模块中获得哪些函数。

min-import

对于 prelude 模块。由于所有 RType 别名都可以从 crate::prelude::R 访问,此功能禁用将别名导入 prelude 模块。

register-routines

注册 R 例程,主要用于宏,因为手动编写此类事情很痛苦。

cfg-if

默认启用,因为编译 no_std 环境的异常处理函数需要 cfg-if。如果你使用 std 功能,则可以禁用它。

public-by-default-even-public-all-is-not-set

虚拟功能。如果你使用 --no-default-feature 禁用它,则不会发生任何事情。

注意

请切换到 prelude 模块页面进行初步了解,因为我想要展示所有文档,大多数私有内容都使用 public-all 功能标志进行文档说明。请勿直接使用它们,因为大多数都有安全包装,直接使用它们是危险的。

用法

版本 0.1.0 提供了一种最快(但很丑)的方法,在函数上实现约 2 倍的速度提升。它们在 0.2.* 中被弃用,因为它们真的很不安全,可能会引起内存泄漏。

当前0.3.0版本与0.2.0版本略有不同,将SEXP<T>重命名为Sexp<T>,并(将)支持类似Sexp<numeric_list>(R::numeric_list)或甚至是一个任意列表Sexp<(T1,T2)>

注意:在即将到来的0.4.0版本中,所有decl_macro可能会被移动到一个单独的crate中,该crate提供宏和proc_macros。这可能只会影响具有默认no_std环境的用户。

0.3.0,将#[no_std]恢复!

在0.3.0中,feature std再次是可选的,这将给我们更快的代码生成速度。

变更

    • 目前,新的方法和来自(Rust类型)的方法都进入SExt,您仍然可以编写Owned<T>::new(),但返回Protected<T>
    • no_std添加一个catch_unwind
    • SEXP<T>移动到Sexp<T>,因此SEXP和Sexp可以在相同的情况下出现。
    • 使用宏2.0隐藏大部分结构和方法,但保留文档以供调试目的。
    • 添加对列表的支持(部分完成。)

语法

#![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

上述程序可以使用测试命令进行测试

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.)))"

依赖关系