When handling ExternOutput conversions, Intercom currently does these conversions one by one. As these conversions may fail, at the moment of failure (which is handled with ? by interrupting the conversions) some of the values may be converted and some aren't.
Foreign representations that require manual memory management (Release calls for COM pointers for example) will leak if the error occurs while such values exist.
The new implementation fixes this in two ways depending on the scenario where the ExternOutput values occur.
Rust-to-Foreign invocations
In Rust-to-Foreign invocations the function ExternOutput values are created in the foreign function and the ownership is handed to Rust. In this case it is enough to ensure that allExternOutput values are converted to managed Rust types before unwrapping the returned ComResults with ?.
Rust-from-Foreign invocations
In Rust-from-Foreign invocations the ExternOutput values are created in Rust and converted to foreign types when returned to the foreign functions. If these conversions fail, Intercom must ensure that all previously converted values are released properly. The values that have yet to be converted are still managed by Rust memory management and will be released as normal.
The implementation here involves OutputGuard<TType> type that holds the TType::ForeignType values. During normal return handling the foreign value is moved out of the OutputGuard without any cleanup but if the OutputGuard is dropped without consuming (as is the case if ? returns while existing OutputGuards are in scope), the OutputGuard cleans up the ForeignTypes. By default this means converting the TType::ForeignType back to TType, which should already handle memory for the successful Rust-to-Foreign scenario.
It is possible for a TType to override the default behavior by providing their own drop_foreign_output implementation. Currently this isn't used, but it is likely that various String-types would put this into use to avoid things like the overhead of the UTF-8 validation when no actual String value is needed.
When handling
ExternOutput
conversions, Intercom currently does these conversions one by one. As these conversions may fail, at the moment of failure (which is handled with?
by interrupting the conversions) some of the values may be converted and some aren't.Foreign representations that require manual memory management (
Release
calls for COM pointers for example) will leak if the error occurs while such values exist.The new implementation fixes this in two ways depending on the scenario where the
ExternOutput
values occur.Rust-to-Foreign invocations
In Rust-to-Foreign invocations the function
ExternOutput
values are created in the foreign function and the ownership is handed to Rust. In this case it is enough to ensure that allExternOutput
values are converted to managed Rust types before unwrapping the returnedComResult
s with?
.Rust-from-Foreign invocations
In Rust-from-Foreign invocations the
ExternOutput
values are created in Rust and converted to foreign types when returned to the foreign functions. If these conversions fail, Intercom must ensure that all previously converted values are released properly. The values that have yet to be converted are still managed by Rust memory management and will be released as normal.The implementation here involves
OutputGuard<TType>
type that holds theTType::ForeignType
values. During normal return handling the foreign value is moved out of theOutputGuard
without any cleanup but if theOutputGuard
is dropped without consuming (as is the case if?
returns while existingOutputGuard
s are in scope), theOutputGuard
cleans up theForeignType
s. By default this means converting theTType::ForeignType
back toTType
, which should already handle memory for the successful Rust-to-Foreign scenario.It is possible for a
TType
to override the default behavior by providing their owndrop_foreign_output
implementation. Currently this isn't used, but it is likely that various String-types would put this into use to avoid things like the overhead of the UTF-8 validation when no actualString
value is needed.