-
Notifications
You must be signed in to change notification settings - Fork 128
r_top_level_exec() and r_parse_vector()
#112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
I'll try to give a more thorough review later, but what do you think about using a Result type instead of a boolean for the return value? I'll have to read further to understand if we can really safely transmute Rust closures (or other FnMut's?) in the way being done here. It may also be considering whether |
|
(yes, definitely) made it so |
|
I'll have a look at adding a similar wrapper around (this is the kind of exercise that is perfect here because I get to practice quite a few rust concepts, but still make something potentially useful) |
kevinushey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM; do you have any reference material discussing the casts being done to get a C function pointer from a Rust closure and when / why that's safe?
| let mut protect = RProtect::new(); | ||
| let call = protect.add(Rf_lang2(r_symbol!("conditionMessage"), *self.condition)); | ||
|
|
||
| RObject::from(Rf_eval(call, R_GlobalEnv)).try_into().unwrap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be the base environment? (in case someone has defined conditionMessage() in the global environment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah probably, this also assumes that conditionMessage() won't itself jump, but I think this is fair.
|
Added the
Example from the tst: let out = r_try_catch_error(|| {
let msg = CString::new("ouch").unwrap();
Rf_error(unsafe {msg.as_ptr()});
R_NilValue
});I've re-implemented #[allow(non_upper_case_globals)]
pub unsafe fn r_parse_vector(code: String) -> ParseResult {
let mut ps : ParseStatus = 0;
let mut protect = RProtect::new();
let r_code = protect.add(crate::r_string!(code));
let lambda = || {
R_ParseVector(r_code, -1, &mut ps, R_NilValue)
};
match r_try_catch_error(lambda) {
Err(_) => ParseResult::Error{
message: geterrmessage()
},
Ok(out) => {
match ps {
ParseStatus_PARSE_OK => ParseResult::Ok(*out),
ParseStatus_PARSE_INCOMPLETE => ParseResult::Incomplete(),
_ => {
ParseResult::SyntaxError{
message: CStr::from_ptr(R_ParseErrorMsg.as_ptr()).to_string_lossy().to_string(),
line: R_ParseError as i32
}
}
}
}
}
}The error case here can definitely be improved to grab information from the condition thrown from Err(_) => ParseResult::Error{
message: geterrmessage()
} |
Not really, I found |
|
A thing that bothers me here is that the closure must return a let out = r_try_catch_error(|| {
let msg = CString::new("ouch").unwrap();
Rf_error(unsafe {msg.as_ptr()});
R_NilValue
});It would be nice to be able to avoid the let out = r_try_catch_error(|| {
let msg = CString::new("ouch").unwrap();
Rf_error(unsafe {msg.as_ptr()});
}) |
|
Related article: https://adventures.michaelfbryan.com/posts/rust-closures-in-ffi/ |
…ink) the template parameter
|
Also following up after #118 this now has:
Because of that, I've been able to implement the pub unsafe fn r_try_catch<F, R, S>(fun: F, classes: S) -> std::result::Result<RObject, RError> where F: FnMut() -> R, MaybeSEXP: From<R>, S : ToRStrings {
r_try_catch_finally(fun, classes, ||{} )
}
pub unsafe fn r_try_catch_error<F, R>(fun: F) -> std::result::Result<RObject, RError> where F: FnMut() -> R, MaybeSEXP: From<R> {
r_try_catch_finally(fun, "error", ||{} )
}I think it's fine to have both |
|
Also, I removed |
kevinushey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, only main concern is avoiding usage of unwrap() in a couple cases.
Co-authored-by: Kevin Ushey <kevin@posit.co>
Co-authored-by: Kevin Ushey <kevin@posit.co>
|
This still needs a little bit of work, but made it so pub unsafe fn r_try_catch_error<F, R>(fun: F) -> Result<RObject>
where
F: FnMut() -> R,
RObject: From<R>i.e. it takes a closure that returns something that can be converted to an |
kevinushey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM; nice work!
|
Thanks. I'll follow up with a pr that calls |
Merge pull request #112 from posit-dev/fix-runtime-integration fix runtime integration -------------------- Commit message for posit-dev/positron-python@d03ba77: fix runtime integration Only register runtimes once. Use `IDisposableRegistry` instead of `ILanguageServerProxy.dispose` to dispose the runtime to delay disposing instead of disposing when `vscode-python` tries to stop the language server. Fixes #658. Authored-by: Wasim Lorgat <mwlorgat@gmail.com> Signed-off-by: Wasim Lorgat <mwlorgat@gmail.com>
Merge pull request #112 from posit-dev/fix-runtime-integration fix runtime integration -------------------- Commit message for posit-dev/positron-python@d03ba77: fix runtime integration Only register runtimes once. Use `IDisposableRegistry` instead of `ILanguageServerProxy.dispose` to dispose the runtime to delay disposing instead of disposing when `vscode-python` tries to stop the language server. Fixes #658. Authored-by: Wasim Lorgat <mwlorgat@gmail.com> Signed-off-by: Wasim Lorgat <mwlorgat@gmail.com>
Related to #109
This adds
r_top_level_exec()as a rust wrapper aroundR_ToplevelExec():outis aResult< {whatever the lambda returns}, {Error = Error::TopLevelExecError}>Maybe this could bepub unsafe fn r_top_level_exec<F, R>(mut f: F -> R) -> Result<R> where F: FnMut() -> Rinstead so that we'd just get the returned value from the block, but I could not figure it out yet.This also add
r_parse_vector()aroundR_ParseVector():This has issues:
R_ParseVector()works, there are two different paths to get an error:*42gives aPARSE_INCOMPLETEthat we translate here to aSyntaxError. This gives an error message and a line.42 + _gives aPARSE_OKbut then throws an error (the reason we have to capture it), this gets translated to anError. This only gives an error message (fromgeterrmessage())The other issue is that
r_top_level_exec()still prints the error, i.e. when running the tests I'm getting:So maybe
r_top_level_exec()is not the right tool here, unless we can get rid of the error somehow ?