How to return {:ok, result} back into Elixir from NifResult<Type> with Rustler and Rust?

To match the Elixir convention, I am trying to return from my Rustler functions {:ok, result} or {:error, error_string}.

I can do the :error case as follows, but can’t solve the :ok case:

fn get_id(index: i64) -> NifResult<String> {
    if index >= 1) {
        return Err(rustler::Error::Term(Box::new("attempt to get index outside range"))); 
    }
    else {
        let hello = "HELLO".to_string();
        return Ok( hello); //HOW TO MAKE THIS RETURN {:ok, "HELLO"} rather than just "HELLO"?
    }
}

With the above code, I am able to get {:error, "attempt to get index outside range"} but I still cannot get {:ok, "HELLO"}.

If I just return Ok(hello); then I just get the result without the {:ok, result} tuple wrapping of it.

I also tried

mod my_atoms {
    rustler::atoms! {
        ok
   }
}

with

        let result = (my_atoms::ok, hello); 
        return Ok(result); 

But this does not work either. I tried ChatGPT out of interest but it is just giving me hallucinations of things that don’t exist (maybe did at one time but don’t now).

It seems logical that if you are going to get {:error, reason} you should also want to get {:ok, result}

How can I do this? Is there some more correct way to do it I am not? Thanks for any help.

Looks like you want to use a Result not a NifResult: Result behaviour difference · Issue #377 · rusterlium/rustler · GitHub

3 Likes

It’s probably enough if you ask in one place and wait for more than two hours for an answer. I’d venture a guess that most people that read the issues on the Rustler repo also from time to time hang around here.

You can do what @jswanner suggested. A definite error in your attempt with the tuple is that the atoms! macro generates functions, not objects. You have to call my_atoms::ok() to get the actual :ok atom.

1 Like

Thanks. That was helpful. Got me to the solution.

If I rewrite the function as:

#[rustler::nif]
fn get_id(index: i64) -> NifResult<String, String> {
    if index >= 1) {
        return Err("hi".to_string()); 
    }
    else {
        return Ok("HELLO".to_string()); 
    }
}

I can get {:ok, "HELLO"} & {:error, "hi"}

Thanks. :slight_smile:

Correction - typo. Just for reference if anyone else is looking in the future the working function is:

#[rustler::nif]
fn get_id(index: i64) -> Result<String, String> {
    if index >= 1) {
        return Err("hi".to_string()); 
    }
    else {
        return Ok("HELLO".to_string()); 
    }
}

You have to use Result, not NifResult as suggested.

1 Like

I was about to point that out because in the linked PR it was clearly stated that using NifResult does not wrap the result in the :ok or :error atoms.

1 Like