Added parameters/return values to signal failure. In particular, we
need a way to signal that the foreign executor has been cancelled/closed
and therefore any futures that depend on it should be halted. This is
needed to fix#1669.
Updated the Rust code to check for executor failures. We need to
release any references passed to the waker callback since that callback
will not run in that case.
Updated the foreign code to handle cancelled futures.
Reworked and updated unit tests to test the new system.
Bumped `UNIFFI_CONTRACT_VERSION` since this requires changing the
scaffolding API. I think this is correct, although you could make the
argument that it's not needed since the async code is still fairly
experimental.
Updated the `uniffi-versioning.md` doc now that
`UNIFFI_CONTRACT_VERSION` lives in `uniffi_meta`.
Set the timeout in Rust rather than the foreign language. I'm not sure
exactly why, but on Kotlin if we see the issue the test simply hangs
rather than exiting with an exception. By setting the timeout in Rust,
we can at least print out an error before the hangs.
Added Python and Swift tests.
```
uniffi-fixture-callbacks-129de7ccace1172c/fixture_callbacks.swift:1067:26: warning: no calls to throwing functions occur within 'try' expression
let result = try swiftCallbackInterface.fromSimpleType(
^
```
NB: the `swift::try` macro is concerned with the containing function calling
subfunctions (it expands to `try` or `try!`) which is not what is needed here,
we care about whether the subfunction being called throws.
Determined from https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Keywords-and-Punctuation
Previously lots of warning were generated of the form:
```
/tmp/target/tmp/uniffi-example-custom-types-2b18f735d09116c0/custom_types.swift:427:13: warning: keyword 'url' does not need to be escaped in argument list
`url`: FfiConverterTypeUrl.read(from: &buf),
^ ~
```
When compiling generated Swift code.
Swift appears to be fairly tollerant of keyswords in some contexts, in
particular:
* only a small subset of keywords need to be quoted when a name is
used as an argument label when calling a function.
* enum variant names do not need to be quoted when they are used, only when
they are defined.
Fixes: #1460
```
uniffi-fixture-coverall-af68e6307d32e36f/coverall.swift:490:16: warning: 'init(bytes:)' is deprecated: replaced by 'init(_:)'
return Data(bytes: try readBytes(&buf, count: Int(len)))
^
uniffi-fixture-coverall-af68e6307d32e36f/coverall.swift:490:16: note: use 'init(_:)' instead
return Data(bytes: try readBytes(&buf, count: Int(len)))
^ ~~~~~~~
```
According to the docs for the [deprecated][] method and the [replacement][]
method the replacement is available in all the same versions as the deprecated
function, so there should be no risk in removing.
AFAICT the deprecation was in 2018/19 timeframe.
[deprecated]: https://developer.apple.com/documentation/foundation/data/3020550-init
[replacement]: https://developer.apple.com/documentation/foundation/data/2852972-init
The generated code was producing a warning (seen a couple of dozen times in the
fixtures):
```
unary_result_alias.swift:373:32: warning: immutable value 'message' was never used; consider replacing with '_' or removing it
case let .AllGoneWrong(message):
^~~~~~~
_
```
The call of `write_fn` on `message` was removed back in 734050dbf1
("Refactoring the callback interface return code").
Comparing with the Kotlin and Python equivalents the pattern is that the
foreign enum/error has the message field but it is not propagated to Rust for
flat enums. So replace with `_` as suggested.
Doing so then results in:
```
unary_result_alias.swift:373:14: warning: 'let' pattern has no effect; sub-pattern didn't bind any variables
case let .AllGoneWrong(_ /* message is ignored*/):
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
So drop the `let` too.
After moving `NewtypeHandle` in the fixture to a submodule I got:
```
error[E0433]: failed to resolve: use of undeclared type `UniffiCustomTypeConverter`
--> fixtures/ext-types/proc-macro-lib/src/lib.rs:168:5
|
168 | uniffi::custom_newtype!(NewtypeHandle, i64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `UniffiCustomTypeConverter`
|
= note: this error originates in the macro `uniffi::custom_newtype` (in Nightly builds, run with -Z macro-backtrace for more info)
```
Giving the full path to the type defined in the scaffolding resolves this.
* Add http-headermap custom type fixture
`http::HeaderMap` is a multi-map so for simplicity we expose as a `sequence` of
headers.
This was broken by https://github.com/mozilla/uniffi-rs/pull/1661 which caused:
```
error: unexpected token
--> /tmp/target/debug/build/uniffi-fixture-ext-types-http-headermap-2750e41fdae052ad/out/http_headermap.uniffi.rs:132:40
|
132 | ::uniffi::custom_type!(r#HeaderMap, std::vec::Vec<r#HttpHeader>);
| ^
```
* Use builtin's `FfiConverter::FfiType` when implementing custom type `FfiConverter`
This avoids needing to match on stringified Rust types.
This is the first part of the fix for the `http-headmap` fixture.
* Allow custom type's builtin to be a `Path` not just an `Ident`
This allows the `http-headermap` test to pass again.
When we execute a future on Kotlin, we create a `jni.Callback` instance
that Rust calls when the Future is ready. We need to hold a reference
to that object or else the JVM will finalize it and when Rust tries to
invoke the callback bad things will happen. In the unit tests this
causes them to stall because the Kotlin coroutine continutation is never
completed.
The `callbackHolder` variable was intended to hold a reference, but it
doesn't seem to be working (see [arg0d's analysis](https://github.com/mozilla/uniffi-rs/pull/1677#issuecomment-1660663156)).
I belive the issue is that variable isn't actually used anywhere so
Kotlin frees it before the coroutine has completed and the reason #1684
fixes the issue is that it uses the variable in the completion handler
(https://github.com/mozilla/uniffi-rs/pull/1684/files#diff-f564b605a6ba32d19bcb47128dc9c5c2f01169e2a41fa60ffaaf0b6eea13845cR34)
This commit changes things so instead of using a local variable, there's
a global set that stores all active callbacks. It seems to fix the
issue for me when using arg0d's `repeat(1000) { ... }` test.
The 'external-types' fixture was testing that a type defined in
another crate could be used in UDL in this crate. It was a little
confusing to have two fixtures with such similar names, so the
two fixtures are now one.
In m-c we're running into linking issues in `uniffi_macros`,
where it's missing symbols coming from `uniffi_core`:
/bin/ld: uniffi_foreign_executor_callback_set: undefined version:
/bin/ld: failed to set dynamic section sizes: bad value
That's most likely this issue on Rust:
https://github.com/rust-lang/rust/issues/111888
It's called out that this likely actually broke because of another PR:
https://github.com/rust-lang/rust/pull/99944
Despite this bug there's a bit of an issue in UniFFI to begin with:
We're exporting `extern "C"` functions from a crate that is a dependency
of some other crates, including `uniffi_macros`, and thus the symbols
land in a part where they are not needed.
However for `uniffi_meta` in particular we don't need much from
`uniffi_core`, so for now we just copy the necessary bits to get it all
working.
This makes library mode work when the dependent crate doesn't include
"lib" in their `crate-type` list. I think that check was leftover from
older code and isn't needed anymore.
* Test string edge cases for Kotlin and Swift
* Kotlin: Throw `CharacterCodingException` on invalid UTF-16 `String`
This exception is produced using
`CharsetEncoder.onUnmappableCharacter(CodingErrorAction.REPORT)`.