I am currently writting a wrapper for a C library, which follows the following convention for all of its functions:
ErrorCode functionName(arg1, arg2, ..., *ptrResult);
The developer is expected to allocate the memory in which the result will be written and pass it through *ptrResult
. The return value indicates if the operation was successful or not.
I am wrapping all functions so they become, in Rust:
fn function_name(arg1, arg2, ...) -> Result<T, ErrorCode>;
This works most of the time, because usually if the returned code is not "success", no result is written on *ptrResult
(in other words we usually don't care about the code AND the result).
But there are a few cases where the function can return a code like "something went wrong but not badly enough to make the call fail". In this case, the error code is not "success", but a value is still written on *ptrResult
. So in this case I want to retrieve both the code and the result.
The thing is that 95% of the time, the Result
pattern works well, so I would like to keep that. Basically I would like to make a structure that can be converted transparently to Result
, and on which I would add a destructure
method, so both these snippets are valid:
// Use the expect() method implemented by Result
let value = some_function().expect("Something went wrong");
// Use the custom destructure() method to match on both the code and the result
let value = match some_function().destructure() {
(ErrorCode::Success, value) => value,
(ErrorCode::PartialSuccess, value) => some_processing(value),
(_, _) => panic!("Something went wrong")
}
Here is the list of solutions I thought about, and why it doesn't work:
- implement
Into<Result<T, ErrorCode>> for MyResult<T>
: requires the developer to manually callinto()
after each call, making the API tedious to use - implement
Deref<Target = Result<T, ErrorCode>>
: doesn't work becausederef
retrieves a reference, while I would like to retrieve a value (that would be consumed byexpect()
ordestructure()
for example) - the last chance solution would be to manually re-implement all the methods and traits of
Result
, but it seems to be way too overkill for what I'm trying to do
I was thinking maybe the macros could help in some way, but I cannot put my finger on how (I must say I have very little experience with macros).
Do you guys have any advice to share on the issue?