Custom unwrapping function

Hello.
Is it possible to write my own function for unwrapping?
The problem is the return value from the function.

pub enum MyEnum
{
    A,
    B,
    C
}


pub enum MyStatus
{
    OK,
    ERROR
}

// if OK return -> MyEnum, if Err return MyStatus::ERR
pub fn my_unwrap(option: Option<MyEnum>) -> MyStatus / MyEnum
{
    match option
    {
        Some(res) => { return res; },
        None => { return MyStatus::ERROR;}
    }
}

It sounds like you're looking for the Result type:

-> Result<T, E>

You're basically recreating it with your MyStatus enum.

In your example:

pub enum MyEnum {
    A,
    B,
    C,
}

pub fn my_unwrap(option: Option<MyEnum>) -> Result<MyEnum, &str> {
    match option {
        Some(res) => Ok(res),
        None => Err("Some error string"),
    }
}

No.
I'm looking for alternatives for code unwrapping code block.

pub struct CallbackArgs{}

unsafe extern "C" fn c_handler(args: *mut CallbackArgs) -> MyStatus
{
    ///...any code
    
    // unwraping code - begin
    let value = match any_variable.option_my_enum
    {
        Some(value) => {value},
        None => { return MyStatus::ERROR; }
    };
    // unwraping code - end

    ///...any code
    
    return MyStatus::OK;
}

Just saying "no" and repeating your question without further clarification doesn't help. What are you trying to unwrap and from what? Like, what's your goal from input/output standpoint?

I don't want to return Result <MyEnum, & str>.
I want to replace block - 'unwrapping code' with something that gives the same result as this block.

Well, as far as I understand your question I would tent to say this is not possible in Rust, as a function signature can only return one specific type and not one type in one case and a complete other type on the other hand.

You could overcome this situation if you would define a trait that both your return value variants implement and than using a trait object as the return type.

trait MyType;
impl MyType for MyEnum {}
impl MyType for MyStatus {}

pub fn my_unwrap(option: Option<MyEnum>) -> Box<dyn MyType>
{
    match option
    {
        Some(res) => { return Box::new(res); },
        None => { return Box::new(MyStatus::ERROR);}
    }
}

However, this part of your example:

// unwraping code - begin
    let value = match any_variable.option_my_enum
    {
        Some(value) => {value},
        None => { return MyStatus::ERROR; }
    };
    // unwraping code - end

could be re-written as

if let Some(value) = any_variable.option_my_enum {
    /* do something with value */
else {
    return MyStatus::ERROR;
}

if you are not happy with the pattern matching using the match expression.

1 Like

This "something" cannot be a function. Note that the Result::unwrap works differently from your example - it panics on error, not returns.

I'm not quite certain what you're asking but I would recommend putting your actual logic in a Rust function since it makes it easier and then convert to FFI types at the top level:

extern "C" fn extern_fn() -> Status {
    inner_fn.map(|_| Status::OK).unwrap_or(Status::ERROR)
}
fn inner_fn() -> Result<(), ()> {
    // Any code
    option_my_enum.ok(())?;
    // Any code

    Ok(())
}
1 Like

How about a macro?

pub struct CallbackArgs{}

unsafe extern "C" fn c_handler(args: *mut CallbackArgs) -> MyStatus
{
    macro_rules! my_try {
        ($expr:expr) => {
            match $expr {
                Some(x) => x,
                None => return MyStatus::ERROR,
            }
        };
    };

    // ...
    
    let value = my_try!(any_variable.option_my_enum);
    
    // ...
    MyStatus::OK
}

Playground

I am not sure if this is what you want, because in your first example you showed you intended to return either the enum or the error, but that is not what your second example is doing.

If you intend to something similar to your first example, you have to remember that you need to return something valid in C, like the following:

#[repr(C)]
struct CHandlerReturn {
    status: MyStatus,
    value: MaybeUninit<MyEnum>,
}

unsafe extern "C" fn c_handler(args: *mut CallbackArgs) -> CHandlerReturn {
    macro_rules! my_try {
        ($expr:expr) => {
            match $expr {
                Some(x) => x,
                None => {
                    return CHandlerReturn {
                        status: MyStatus::ERROR,
                        value: MaybeUninit::uninit(),
                    }
                }
            }
        };
    };

    // ...
    let value = my_try!(any_variable.option_my_enum);

    // ...
    CHandlerReturn {
        status: MyStatus::OK,
        value: MaybeUninit::new(value),
    }
}

Playground