extendr / rextendr

An R package that helps scaffolding extendr-enabled packages or compiling Rust code dynamically
https://extendr.github.io/rextendr/
Other
184 stars 27 forks source link

[Feature Proposal]: Separate `rust_eval()` into compilation and evaluation steps for internal use #123

Closed Ilia-Kosenkov closed 3 years ago

Ilia-Kosenkov commented 3 years ago

I propose to modify rust_eval() and separate code compilation and import from invocation. Currently, everything happens within rust_eval(): Compilation https://github.com/extendr/rextendr/blob/584d67e194b1a8f46745e005e870f0b43f5c9f16/R/eval.R#L41-L49 Execution https://github.com/extendr/rextendr/blob/584d67e194b1a8f46745e005e870f0b43f5c9f16/R/eval.R#L50 Cleanup https://github.com/extendr/rextendr/blob/584d67e194b1a8f46745e005e870f0b43f5c9f16/R/eval.R#L51

In order to capture cargo output and provide better error messages, we need to be able to inject code in-between compilation and execution. This affects {knitr} engines.

My proposed solution is to create an unexported function, which performs compilation and loads library, but instead of evaluation returns a function, which can be called at some later point. This function can be called only once, and upon invocation, it also registers handles for resource cleanup. If such function is called rust_eval_deferred, then the current implementation of rust_eval() can be replaced by

rust_eval_deferred <- function(...) { 
  # logic goes here 
  return (function() { })
}
rust_eval <- function(...) {
  rust_eval_deferred(...)()
}

This will allow us to separately control how stdout is captured during compilation and during invocation. The former is needed for cargo error parsing, the latter -- to be able to knit any rprintln!() into the document.

I have a PoC at https://github.com/Ilia-Kosenkov/rextendr/blob/ebeb1ed2e55ae67c9cb1288aa048896f6811bb64/R/eval.R#L46-L104

clauswilke commented 3 years ago

Fine by me.