Unreleased (ReleaseDate)
- Now savvy no longer uses
SETLENGTH
, which is a so-called "non-API" thing.
v0.6.0 (2024-04-20)
-
savvy-cli test
now parses test modules marked with#[cfg(savvy_test)]
instead of#[cfg(test)]
. The purpose of this change is to letcargo test
run for the tests unrelated to a real R sessions. -
Savvy now generates different names of Rust functions and C functions; previously, the original function name is used for the FFI functions, but now it's
savvy_{original}_ffi
. This change shouldn't affect ordinary users.This change was necessary to let
#[savvy]
preserve the original function so that we can write unit tests on the function easily. One modification is that the function is made public. For more details, please read the Testing section in the guide. -
The generated R wrapper file is now named as
000-wrappers.R
instead ofwrappers.R
. This makes the file is loaded first so that you can override some of the R functions (e.g., aprint()
method for an enum) in another R file. The old wrapper filewrappers.R
is automatically deleted bysavvy-cli update
-
Added a function
eval_parse_text()
, which is an equivalent to R's idiomeval(parse(text = ))
. This is mainly for testing purposes. -
Added a function
is_r_identical()
, which is an equivalent to R'sidentical()
. This is mainly for testing purposes. -
Added a function
assert_eq_r_code()
if the first argument has the same data as the result of the R code of the second argument.Example:
let mut x = savvy::OwnedRealSexp::new(3)?; x[1] = 1.0; x[2] = 2.0; assert_eq_r_code(x, "c(0.0, 1.0, 2.0)");
-
savvy-cli test
now picks[dev-dependencies]
from the crate'sCargo.toml
as the dependencies to be used for testing. -
savvy-cli test
got--features
argument to add features to be used for testing.
v0.5.3 (2024-04-16)
-
Savvy now catches crash not only on the debug build, but also on the release build if
panic = "unwind"
. Instead, nowsavvy-cli init
generates aCargo.toml
with a release profile ofpanic = "abort"
. You need to modify this setting if you really want to catch panics on the release build. -
savvy-cli update
now ensures.Rbuildignore
contains^src/rust/.cargo$
and^src/rust/target$
. -
savvy-cli test
now uses OS's cache dir instead of the.savvy
directory.
- Now
savvy-cli test
works for other crates than savvy.
v0.5.2 (2024-04-14)
-
Now savvy's debug build (when
DEBUG
envvar is set totrue
, i.e.,devtools::load_all()
), panic doesn't crash R session and shows bactrace. This is useful for investigating what's the cause of the panic.Please keep in mind that, in Rust, panic is an unrecoverable error. So, not crashing doesn't mean you are saved.
-
savvy-cli test
no longer relies on the savvy R package.
-
Fixed a bug in
try_from_iter()
when the actual length is different than the size reported bysize_hint()
. -
savvy-cli test
now uses the local crate as the path dependency, instead of using the savvy crate fixedly.
v0.5.1 (2024-04-13)
-
An experimental new subcommand
savvy-cli test
runs tests by extracting and wrapping the test code with a temporary R package. This is because savvy always requires a real R session, which meanscargo test
doesn't work. Note that this relies on the savvy R package. Please install it before trying this.install.packages("savvy", repos = c("https://yutannihilation.r-universe.dev", "https://cloud.r-project.org"))
-
savvy-cli init
now generatesMakevars
that supports debug build whenDEBUG
envvar is set totrue
(i.e., indevtools::load_all()
).
v0.5.0 (2024-04-05)
-
To support enum properly (the details follow), now savvy requires to put
#[savvy]
macro also onstruct
.#[savvy] // NEW! struct Person { pub name: String, } #[savvy] impl Person {
This might be a bit inconvenient on the one hand, but, on the other hand, several good things are introduced by this change! See the New Features section.
-
Now
#[savvy]
macro supports enum to express the possible options for a parameter. This is useful when you want to let users specify some option without fear of typo. See the guide for more details.Example:
/// @export #[savvy] enum LineType { Solid, Dashed, Dotted, } /// @export #[savvy] fn plot_line(x: IntegerSexp, y: IntegerSexp, line_type: &LineType) -> savvy::Result<()> { match line_type { LineType::Solid => { ... }, LineType::Dashed => { ... }, LineType::Dotted => { ... }, } }
plot_line(x, y, LineType$Solid)
-
Savvy now allows
impl
definition over multiple files. It had been a headache that it wouldn't compile when you specified#[savvy]
onimpl
of a same struct multiple times. But now, you can split theimpl
not only within a same file but also over multiple files. -
OwnedListSexp
andListSexp
gainsunchecked_*()
variants of theset
andget
methods for a fast but unsafe operation. Thanks @daniellga!
v0.4.2 (2024-04-01)
-
OwnedIntegerSexp
and etc now havetry_from_iter()
method for constructing a new instance from an iterator.Example:
#[savvy] fn filter_integer_odd(x: IntegerSexp) -> savvy::Result<Sexp> { // is_na() is to propagate NAs let iter = x.iter().copied().filter(|i| i.is_na() || *i % 2 == 0); let out = OwnedIntegerSexp::try_from_iter(iter)?; out.into() }
-
OwnedIntegerSexp
and etc now havetry_from_slice()
method for constructing a new instance from a slice or vec. This conversion is and has been possible viatry_from()
, but this method was added for discoverability. -
OwnedIntegerSexp
and etc now havetry_from_scalar()
method for constructing a new instance from a scalar value (e.g.i32
). This conversion is and has been possible viatry_from()
, but this method was added for discoverability. -
savvy-cli update
andsavvy-cli init
now tries to parse the Rust files actually declared bymod
keyword.
v0.4.1 (2024-03-30)
Sexp
losesis_environment()
method becuase this isn't useful, considering savvy doesn't support environment.
-
get_dim()
andset_dim()
are now available also onSexp
. -
Now savvy allows to consume the value behind an external pointer. i.e.,
T
instead of&T
or&mut T
as the argument. After getting consumed, the pointer is null, so any function call on the already-consumed R object results in an error. See the guide for more details.Example:
struct Value {}; struct Wrapper { inner: Value } #[savvy] impl Value { fn new() -> Self { Self {} } } #[savvy] impl Wrapper { fn new(value: Value) -> Self { Self { inner: value } } }
v <- Value$new() w <- Wrapper$new(v) # value is consumed here. w <- Wrapper$new(v) #> Error: This external pointer is already consumed or deleted
-
Sexp
now hasassert_integer()
etc to verify the type of the underlying SEXP is as expected.
v0.4.0 (2024-03-27)
-
#[savvy]
on a struct'simpl
now generates the same name of R object that holds all the accociated functions. For example, previously the below code generates a constructorPerson()
, but now the constructor is available asPerson$new()
.struct Person { pub name: String, } /// @export #[savvy] impl Person { fn new() -> Self { Self { name: "".to_string(), } } }
- A struct marked with
#[savvy]
can be used as the return type of the associated function. In conjunction with the change in v0.3.0, now a user-defined struct can be used more flexibly than before. Please refer to the "Struct" section of the guide - An experimental support on complex is added under
compex
feature flag.ComplexSexp
andOwnedComplexSexp
are the corresponding Rust types. OwnedIntegerSexp
and etc now haveset_na(i)
method for shorthand ofset_elt(i, T::na())
. This is particularly useful forOwnedLogicalSexp
because its setter interfaceset_elt()
only acceptsbool
and no missing values.
- An expert-only method
new_without_init()
now skips initialization as intended.
v0.3.0 (2024-03-24)
-
Now user-defined struct can be used as an argument of
#[savvy]
-ed functions. It must be specified as&Ty
or&mut Ty
, notTy
.Example:
struct Person { pub name: String, } #[savvy] impl Person { fn get_name(&self) -> savvy::Result<savvy::Sexp> { let name = self.name.as_str(); name.try_into() } } #[savvy] fn get_name_external(x: &Person) -> savvy::Result<savvy::Sexp> { x.get_name() }
- Previously,
savvy-cli init
andsavvy-cli update
didn't handle the package name properly ("packageName" vs "package_name"). Now it's fixed.
- While this is described in the New features section, it was already allowed to
specify user-defined structs as argument if the user defines the necessary
TryFrom
implementations propoerly. At that time, specifying it without&
was possible, but now it's not allowed. Anyway, as this was undocumented and expert-only usage, I expect no one notices this breaking change.
v0.2.20 (2024-03-23)
v0.2.19 (2024-03-23)
LogicalSexp
andOwnedLogicalSexp
now haveas_slice_raw()
method. This is an expert-only function which might be found useful when you really need to distinguish NAs.
savvy-cli init
now generates<dllname>-win.def
to avoid the infamous "export ordinal too large" error on Windows.
v0.2.18 (2024-03-11)
- The version requirement is a bit more strict now.
v0.2.17 (2024-03-10)
get_dim()
now returns&[i32]
instead ofVec<usize>
to avoid allocation. If the matrix library requiresusize
, you need to convert thei32
tousize
by yourself now. Accordingly,set_dim()
now accepts both&[i32]
and&[usize]
.
v0.2.16 (2024-03-03)
fake-libR
feature is withdrawn. Instead, Windows users can add this build configuration to avoid the linker error:[target.x86_64-pc-windows-msvc] rustflags = ["-C", "link-arg=/FORCE:UNRESOLVED"]
v0.2.15 (2024-03-02)
- Previously, if a crate uses savvy,
cargo test
fails to compile on Windows even if the test code doesn't use the savvy API at all. This is because the symbols from Rinternals.h needs to be resolved. You can addsavvy
withfake-libR
feature indev-dependencies
to avoid this issue.
- Reject invalid external pointers so that the R session doesn't crash.
v0.2.14 (2024-02-14)
savvy-cli update
andsavvy-cli init
now correctly overwrite the existing files.
v0.2.13 (2024-02-14)
- The savvy-cli crate now requires Rust >= 1.74 because this is clap's MSRV.
v0.2.12 (2024-02-14)
savvy-cli init
now addsSystemRequirements
to theDESCRIPTION
file.
savvy-cli
now works if it's invoked outside of the R package directory.savvy-cli init
now generates the build configuration with a workaround for the case of thegnu
toolchain on Windows.
v0.2.11 (2024-02-04)
v0.2.10 (2024-02-04)
- Fix the wrong implementation of
to_vec()
.
v0.2.9 (2024-01-27)
Function.call()
now usesFunctionArgs
to represent function arguments. This is necessary change in order to protect function arguments from GC-ed unexpectedly. The previous interface requires users to passSexp
, which is unprotected.Function.call()
now doesn't require the environment to be executed because it rarely matters. Accordingly,Environment
is removed from the API.
v0.2.8 (2024-01-26)
-
savvy-cli init
now producesMakevars.in
andconfigure
instead ofMakevars
in order to support WebR transparently. One limitation on Windows is thatconfigure
cannot be set executable; you have to run the following command by yourself.git update-index --add --chmod=+x ./configure
- Add an experimental support for function and environment.
v0.2.7 (2024-01-25)
- (Experimentally) support WebR by not using
R_UnwindProtect()
.
v0.2.6 (2024-01-20)
- Fix misuses of
Rf_mkCharLenCE()
which caused compilation error on ARM64 Linux.
v0.2.5 (2024-01-20)
ListSexp
now returns anSexp
instead of aTypedSexp
. Use.into_typed()
to convert anSexp
to aTypedSexp
.
- Add
is_null()
. - Add
as_read_only()
toOwnedListSexp
as well. - Add
cast_unchecked()
andcast_mut_unchecked()
for casting an external pointer to a concrete type. Note that this is only needed for "external" external pointers.
v0.2.4 (2024-01-15)
v0.2.2 (2024-01-15)
r_print!
andr_eprint!
are now macro that wrapsformat!
, so you can use them just like Rust'sprint!
macro. There are alsor_println!
andr_eprintln!
available.
- Support scalar
usize
input. - Add methods to access and modify attributes:
get_attrib()
/set_attrib()
get_names()
/set_names()
get_class()
/set_class()
get_dim()
/set_dim()
- A struct marked with
#[savvy]
now hastry_from()
forSexp
.
- Newly-created R vectors (
Owned*Sexp
) are now properly initialized. If you really want to skip the initialization for some great reason, you can usenew_without_init()
instead ofnew()
. #[savvy]
now acceptssavvy::Sexp
as input.