I'm trying to iterate on the contributor experience for UniFFI,
both to support new team members coming on board and to support
additional external contributors. As a start, this:
* Adds a contributing.md file with some concrete steps on how
to get up and running.
* Cleans up the README, linking out to more thorough docs
rather than brain-dumping a bunch of stuff into a single place.
* In particular, some motivational material has moved into a
new "Motivation" section of the user guide.
* Moves all scaffolding-related code into its own sub-module,
to make it easier to describe how to navigate the code.
Fixes#413.
Prior to this commit, the `uniffi-bindgen` command would use `cargo metadata`
to discover the version of uniffi being used by the target crate, and would
error out if did not match the version of uniffi-bindgen itself.
Unfortunately, this approach is not reliable when the target crate is being
compiled as a dependency rather than as the primary crate. The build process
may pick a version of uniffi based on the `Cargo.lock` of the primary crate
or based on resolving compatible versions with other dependencies, while
while `cargo metadata` will report the verison of uniffi that would be used
if you built the target crate in isolation.
To avoid these potential sources of error, this commit switches to an approach
based on static assertions, in two halves:
* When generating the Rust scaffolding, we emit a call to a new
macro `uniffi::assert_compatible_version!(v)` and pass it a static
string constant representing the version of uniffi_bindgen that
generated the code.
* When compiling the resulting code as part of a uniffied crate, the
`assert_compatible_version!` macro will check the static string against
the version of uniffi being used in the build, producing a compile-time
failure if they do not match.
This is a slightly worse consumer experience because the error message
isn't as good, but it's more reliable, so I think it's a win overall.
Be warned, I had to do some terrible things to perform this check in
a compile-time const context on stable Rust :-/
I've also taken the opportunity to try out the `trybuild` crate to
write a testcase for the actual compiler error message generated
by the macro. As we come to iterate more on the developer experience,
I expect `trybuild` or something like it will become pretty important.
Prior to this commit, the only "tests" we had for the generated code
were a small set of example scripts in the various target languages,
and we could "test" them by manually executing the script and seeing
whether it printed plausible output.
With this commit, those scripts can now be proper testcases. It has
involved a fair bit of restructuring, but broadly:
* The crate and its examples are now part of a single workspace,
so `cargo test` in the top-level directory will test them all.
* There is a new `uniffi_macros` crate with a single macro called
`build_foreign_language_testcases!`. Given a list of script files,
it will generate a testcase shim for each one, executing the file
via an appropriate interpret and failing the test if it does not
exit successfully.
* The various example crates have had their example scripts converted
into testcases in this manner.