FFI function calls currently use 2 methods to return results:
The return value of the function is used for successful results
The RustCallStatus out pointer is used for error results and also stores the call_status field which we use to determine if the call was successful or not.
If we made it so RustCallStatus stored the return value as well, then it would simplify several aspects of bindings generation:
C-like languages make a strict distinction between functions that return values and those that don't. This means code like {{ return_type }} return_value = scaffolding_call(...);, since it would be illegal for void returns. Instead we need to create a branch in the template logic and handle both cases separately, which gets messy quickly. By storing the return value in RustCallStatus we can eliminate this branch in most places and simplify the code.
Python cannot return structs from callback functions. This means that callback methods must return their values via an out-pointer. If we return values via RustCallStatus then we could use the same FFI for Rust calls and callback interface calls.
In general, it seems simpler to return everything in one place than in two places.
Maybe we should return the struct to RustCallResult to signify that it's also storing the return value now.
Note: if we implemented this, something similar to the void return issue would arise since C struct fields can't be zero-sized. However, there are a couple fairly simple solutions to that:
We currently solve that for async methods by generating a unit type field on the Rust side and leaving out the field on the foreign side. This has worked okay in practice
We could use a u8 placeholder value for this. If we placed this field next to the i8code field, then it wouldn't take up any extra space in the struct.
I don't think this should give us a significant performance hit, but we should measure that.
FFI function calls currently use 2 methods to return results:
RustCallStatus
out pointer is used for error results and also stores thecall_status
field which we use to determine if the call was successful or not.If we made it so
RustCallStatus
stored the return value as well, then it would simplify several aspects of bindings generation:{{ return_type }} return_value = scaffolding_call(...);
, since it would be illegal for void returns. Instead we need to create a branch in the template logic and handle both cases separately, which gets messy quickly. By storing the return value inRustCallStatus
we can eliminate this branch in most places and simplify the code.RustCallStatus
then we could use the same FFI for Rust calls and callback interface calls.Maybe we should return the struct to
RustCallResult
to signify that it's also storing the return value now.Note: if we implemented this, something similar to the void return issue would arise since C struct fields can't be zero-sized. However, there are a couple fairly simple solutions to that:
u8
placeholder value for this. If we placed this field next to thei8
code
field, then it wouldn't take up any extra space in the struct.I don't think this should give us a significant performance hit, but we should measure that.