Closed danielpclark closed 6 years ago
Looking at the PR https://github.com/tildeio/helix/pull/64 it seems that in order for me to use protect
I need to pass it an extern "C" fn
in order for it to work. He has two macros doing this in the PR ruby_safe_f
and ruby_funcall
.
What I'm looking to do is have an implementation of the send
method you have to operate with Ruby's rb_protect
. I'd like to name it protect_send
and protect_public_send
. This way we won't ever crash our program from exceptions being raised from Ruby. Our return type can be Result<T, AnyObject>
or Result<AnyObject, AnyObject>
. Look at my eval implementation to see what I mean.
I believe I've discovered the issue. Some of the updates done to make the thread code work also needs to be done to protect. I'm looking at how to fix it.
The first thing to note is the type for F needs to change from
pub fn protect<F>(func: F) -> Result<Value, i32>
where
F: FnOnce(),
{
vm::protect(func)
}
to
pub fn protect<F>(func: F) -> Result<Value, i32>
where
F: 'static + FnOnce() -> Value,
{
vm::protect(func)
}
Just like what was done for the thread methods. This allows closures to be passed in.
Then a new problem arises. The Value
now returned from protect is wrong.
Format is Ruby => ValueType
nil
=> Hash // Wrong Value
type returnedfalse
=> None // Okay ¯\_(ツ)_/¯true
=> Symbol // Wrong Value
type returnedString
=> Hash // Wrong Value
type returnedFixnum
=> Fixnum // Correct typeFloat
=> Class // Wrong Value
type returnedI suspect it may have to do with Value
going through the C API to Rust twice.
And now a segfault. Yeah, rb_protect
needs to be rewritten. The Helix PR should be helpful: https://github.com/tildeio/helix/pull/64
I figured it out. It was rather simple in the end. Even if I did spend two days learning a lot in the process of trying to get it to work.
Here's the diff that's needed:
-pub fn protect<F>(func: F) -> Result<Value, c_int>
+pub fn protect<F, R>(func: F) -> Result<Value, c_int>
where
- F: FnOnce(),
+ F: FnOnce() -> R,
I'll include it in my protect_send
PR.
I've been trying to guess at how to use it but I haven't been able to get anything working. I was able to implement a form of
eval_protect
but that was entirely different from this. Could you show me an example? Thanks!