14个版本
0.7.0 | 2022年1月17日 |
---|---|
0.6.3 | 2021年4月27日 |
0.6.0 | 2021年3月4日 |
0.5.0 | 2021年1月8日 |
0.1.1 | 2020年3月29日 |
#358 在 过程宏 中
每月下载 32 次
41KB
806 行
xladd-derive
宏,帮助您在Rust中轻松编写Excel用户定义函数
版本 0.7.0 发布说明
修复了崩溃错误,支持异步函数,并添加了对单线程函数的支持
版本 0.6.3 发布说明
当范围包含#NA或#DIV/0时,会填充f64::NAN。可能会破坏假设0.0的代码
版本 0.6.2 发布说明
如果从范围单元格返回xlTypeMulti,xladd会返回一个null值。
版本 0.6.1 发布说明
xladd中集成了一些小的错误修复
版本 0.6 发布说明
更新到使用ndarray 0.14,支持sref,允许在Excel中使用索引和偏移量范围。一些小的错误修复
版本 0.5 发布说明
- 主要新功能是数组现在可以长到1078,576行,这是Excel支持的最大长度
- 为了支持这一点,尽可能地对代码进行性能分析,以减少数组之间的复制。我相信还可以进行进一步改进
- 现在支持异步UDF。它们在Excel中的表现不错,但拥有太多这样的函数会搞乱Excel的依赖关系管理。但是,函数被标记为线程安全,应该在Rust中(无全局变量)执行,因此您应该没问题。但要注意覆盖问题
- 现在支持make_row和make_col变体数组,以帮助返回表格。
- RTD和Ribbon Bar支持即将推出
版本 0.4 发布说明
新功能
- 之前,当从Excel调用函数时,如果用户参数输入错误,会返回一个通用的“错误”。现在我们得到“函数[xxx]缺少参数[name]”,这是一个更好的用户体验。
- 它还会捕获期望特定类型但无法解析的情况。
- 已添加跟踪日志功能。如果启用了日志并且设置为LevelFilter::Trace级别,则可以获取每个函数调用、传递的参数和结果值的日志。即使禁用,这也对性能产生了一定的影响。建议创建一个Excel UDF(用户定义函数),例如
enable_trace_logging
,将日志输出到文件,以便在测试工作表中按需调用。 - 在Excel中将NaN值转换为#N/A。当用户输入超出范围并产生NAN值时,我发现这很有用。而不是崩溃或跳过,我们在Excel中得到一个#NA,表示我们需要检查输入。
- 添加了对log::* crate的依赖。
0.3版本发布说明
新功能
- 主要新功能是可以通过NDArray使用2维数组进行输入和输出。
- 添加了一个功能标志"使用_ndarray"。但我不知道如何将其自动传递给xladd,如果旧版本的crate没有这个功能标志?欢迎提交PR。这允许您使用Array2或Array2类型作为输入或输出参数。这解决了之前2维数组的问题,之前的解决方案最多只是权宜之计。仍然支持使用&[f64],如之前一样,对于单列或单行数据仍然有意义。仍然支持使用(Vec,usize)作为返回类型,但我认为它很丑,因为它并没有真正显示开发者的意图。
错误修复
- 如果您指定了一个数组(vec或array2)并且您正在拖动一系列值,则第一个单元格实际上被发送为一个单独的f64,而不是一个范围。我之前没有处理这种情况,可能会导致崩溃。
0.2版本发布说明
- 添加了一个新功能:使用prefix可以为您的函数命名。以前,所有导出的Excel函数都称为"xl_myfunction",现在通过设置
prefix = "project_"
,您的导出将被重命名为project_myfunction
。如果没有指定,则默认为"xl_"。 - 添加了rename,它可以将Excel公开的函数重命名为指定的名称。前缀仍然有效。
为什么?
我发现通过拖放快速在Excel中创建示例GUI非常好,这对于原型设计非常有用。编写测试函数并能够交互式地传递各种数据给它是一种有用的功能。
背景
我发现xladd来自MarcusRainbow,它允许创建用于Excel的原始API用户定义函数。我对它并不完全满意,并向他的项目提交了几个PR,但没有收到任何回应,所以我fork了他的项目,并继续添加我认为合适的功能。
但仍然很痛苦,我想学习关于proc-macros的知识,所以创建了这个proc-macro crate,以便更容易地在Rust中编写函数。
用法
添加
[lib]
crate-type = ["cdylib"]
[dependencies]
xladd-derive= {"^0.4" }
xladd = {git="https://github.com/ronniec95/xladd" , features=["use_ndarray"] } # Needed to patch the old abandoned crate
到您的Cargo.toml中
编写一个Rust函数,并添加以下注解#[xl_func()]
,例如
// These imports are needed from xladd
use xladd::registrator::Reg;
use xladd::variant::Variant;
use xladd::xlcall::LPXLOPER12;
use xladd_derive::xl_func;
use log::*; // Needed from 0.4.* onwards to give tracing
#[xl_func()]
fn add(arg1: f64, arg2: f64) -> Result<f64, Box<dyn std::error::Error>> {
// No comments in this method, defaults will be allocated
Ok(arg1 + arg2)
}
/// This function adds any number of values together
/// * v - array of f64
/// * ret - returns the sum0
#[xl_func()]
fn add_array(v: &[f64]) -> Result<f64, Box<dyn std::error::Error>> {
// Comments will be filled into the Excel function dialog box
Ok(v.iter().sum())
}
/// This function adds any number of values together
/// * v - array of f64
/// * ret - returns the sum
#[xl_func(category="MyCategory")] // Custom attribute to assign function to a particular category
fn add_array_v2(v: &[f64]) -> Result<(Vec<f64>, usize), Box<dyn std::error::Error>> {
// Comments will be filled into the Excel function dialog box
// This returns a 2d array to excel using a (vec,usize) tuple. Note that if v.len() / columns != 0 you will have missing values
Ok((v.to_vec(), 2))
}
use ndarray::Array2;
/// 2d arrays can now be accepted and returned opening up a lot more possibilities for interfacing with Excel
#[xl_func(category = "OptionPricing", prefix = "my", rename = "baz")]
fn add_f64_2(a: Array2<f64>) -> Result<Array2<f64>, Box<dyn std::error::Error>> {
Ok(Array2::from_elem([2, 2], 0.0f64))
}
目前有一些限制,我希望将来去除它们
您的函数的返回类型可以是任何基本类型的Result
- f32
- f64
- i32
- i64
- bool
- String(所有者)
或
- (Vec<[基本类型]>,usize)
第二个参数是列数。这允许Excel处理二维数据的数组。该宏将根据数组的尺寸计算行数。
我在想,如果有人需要的话,可以让输入的 &[]
数组也成为一个元组。
参数以LPXLOPER12形式传递,然后被强制转换为Rust类型。强制转换错误将通过trace!()日志报告。如果你通过命令行使用env-logger或simplelog运行Excel,可以将这些输出到文件中进行调试。
文档
以下是对文档注释的解释方式
/// This is a normal multiline comment that
/// will be used as a description of the function
/// * arg1 - This argument must be formatted with a `* <name> -` and will be used in the argument description
/// * ret - This is a special return type argument which will appended to the description of the function
多线程
Excel会使用机器上所有的核心,但它依赖于你的UDFs是线程安全的。Rust是支持多线程的,但如果你正在读写文件,要小心。
如果你想通过属性来控制这个方面,请告诉我。
与Excel注册
当Excel启动时,它会调用你的.dll中的这个函数。宏为你生成register_*函数,所以请遵循以下模板。如果有人知道如何自动从proc-macro中确定这些,请与我联系,或者提交一个PR。
// For excel to register this XLL ensure `no_mangle` is specified
#[no_mangle]
pub extern "stdcall" fn xlAutoOpen() -> i32 {
let reg = Reg::new();
register_add(®);
1 // Must return 1 to signal to excel SUCCESS
}
xladd依赖
由于我似乎无法联系到xladd crate的原作者MarcusRainbow,所以我创建了一个分支。因此,在Cargo.toml
中,你需要添加github依赖项xladd = { git ="https://github.com/ronniec95/xladd"}
。如果这有问题,请告诉我,我可以看看是否有更好的方法。
不安全代码 & Excel兼容性
由于xladd包调用Windows C api,因此它是固有不安全的。此包使用LPXLOPER12 api来与Excel兼容,因此兼容2007年以后的版本。如果插件不工作,请检查你的Excel是否与你的rustc
编译器具有相同的位数(32位或64位)。在许多组织中,Excel通常安装为32位,而你的rustc编译器可能是64位。这当然不会工作。
尚未处理
异步方法。我没有这个需求,尤其是由于网络和IO类型的工作通常在Excel内部完成得更好。
我还想添加RTD支持,这样你就可以订阅实时数据。
调试
在VSCode中,你可以创建一个调试配置,并将program
更改为
"program": "C:/Program Files/Microsoft Office/root/Office16/EXCEL.EXE",
这将启动Excel,但你可以设置断点在你的代码中。
依赖项
~1.9–2.7MB
~53K SLoC