Developers
iroh-ffi uses for building the different language bindings.
General
Translating the iroh API into iroh-ffi bindings
Use these general guidelines when translating the rust API featured in the rust
iroh library with the API we detail in this crate:
PathBuf->StringBytes,[u8], etc -> Vec- Any methods that stream files or have
Readerinputs or outputs should instead expect to read from or write to a file. Also, see if it's logical for any structs or enums that have a method to return aReaderto instead havesizemethod, so that the user can investigate the size of the data before attempting to save it or load it in memory. - Any methods that return a
Streamof structs (such as alistmethod), should return aVecinstead. You should also add a comment that warns the user that this method will load all the entries into memory. - Any methods that return progress or events should instead take a call back. Check out the
Doc::subscribemethod and theSubscribeCallbacktrait for how this should be implemented - Most methods that return a
Resultshould likely get their own uniqueIrohErrors, follow the pattern laid out inerror.rs. - Except for unit enums, every struct and enum should be represented in the
udlfile as an interface. It should be expected that the foreign language use constructor methods in order to create structs, and use setters and getters to manipulate the struct, rather than having access to the internal fields themselves. - Anything that can be represented as a string, should have a
to_stringandfrom_stringmethod, egNamespaceId,DocTicket - Enums that have enum variants which contain data should look at the
SocketAddrorLiveEventenums for the expected translation.
Testing
Please include tests when you add new pieces of the API to the ffi bindings
Languages
Kotlin
- See
README.kotlin.mdfor setup - Build using
./make_kotlin.sh - Tests using
./gradlew testfrom./kotlin
Python
Development setup
- Install for python development and packaging.
- Create and activate a virtual environment
- Install
uniffi-bindgenwithpip maturin buildwill build a wheel intargets/wheelsmaturin developwill build the wheel and install into the current virtual env. It expects you to usevirtualenvto manage your virtual environment.
See below for example commands that do all this.
Running the example
This repo includes a very small, but working example for using the python API, at python/main.py.
To run it with the latest version of iroh published on pypi:
# Install iroh with pip
# Run the example
To run with a locally-built wheel:
# Create and activate a virtual env
# Install dependencies
# Build wheel
# Run the example
Testing
We use to test the python API.
Execute the following commands to prepare and run all tests:
# Create and activate a virtual env
# Install dependencies
# Build wheel
# Run tests
When developing the python API, create a test file for each rust module that you create, and test all pieces of the API in that module in the python test file. The file should be named [MODULENAME]_test.py.
For example, the iroh::net ffi bindings crate should have a corresponding net_test.py file.
Building portable wheels
Invoking maturin build will build a wheel in target/wheels. This
will likely only work on your specific platform. To build a portable
wheel for linux use:
docker run --rm -v $(pwd):/mnt -w /mnt quay.io/pypa/manylinux_2_28_x86_64 /mnt/build_wheel.sh
Translations
Uniffi translates the rust to python in a systematic way. The biggest discrepancy between the rust and python syntax are around how new objects are constructed
- constructor methods w/
newname:Ipv4Addr::new(127, 0, 0, 1)in rust would beIpv4Addr(127, 0, 0, 1)in python - constructor methods with any other name in rust:
SocketAddr::from_ipv4(..)in rust would beSocketAddr.from_ipv4(..)in python - method names will stay the same:
SocketAddr.as_ipv4in rust will be calledSocketAddr.as_ipv4in python - unit enums will have the same names:
SocketAddrType::V4in rust will beSocketAddrType.V4in python - methods that return
Resultin rust will potentially throw exceptions on error in python