diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6322c71..9ff3cc0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,4 +60,36 @@ jobs: - name: Clippy if: ${{ matrix.rust.version != '1.48.0' }} run: cargo clippy ${{ matrix.build-args }} -- -D warnings + + build-ffi: + name: Build FFI + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./negentropy-ffi + strategy: + matrix: + rust: + - version: stable # STABLE + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-ffi-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} + - name: Set default toolchain + run: rustup default ${{ matrix.rust.version }} + - name: Set profile + run: rustup set profile minimal && rustup component add clippy + - name: Build + run: cargo build + - name: Tests + run: cargo test + - name: Clippy + run: cargo clippy -- -D warnings \ No newline at end of file diff --git a/.gitignore b/.gitignore index b1f6010..921855f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /target -/Cargo.lock *.svg perf.data perf.data.old \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5eafb3f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,21 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "harness" +version = "0.1.0" +dependencies = [ + "negentropy", +] + +[[package]] +name = "negentropy" +version = "0.3.1" + +[[package]] +name = "perf" +version = "0.1.0" +dependencies = [ + "negentropy", +] diff --git a/Makefile b/Makefile index 7269187..a22786a 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ precommit: cargo fmt --all -- --config format_code_in_doc_comments=true cargo clippy -p negentropy && cargo clippy -p negentropy --no-default-features cargo test -p negentropy && cargo test -p negentropy --no-default-features + cd ./negentropy-ffi && make precommit bench: RUSTFLAGS='--cfg=bench' cargo +nightly bench -p negentropy @@ -13,4 +14,4 @@ clean: cargo clean loc: - @echo "--- Counting lines of .rs files (LOC):" && find src/ -type f -name "*.rs" -exec cat {} \; | wc -l \ No newline at end of file + @echo "--- Counting lines of .rs files (LOC):" && find negentropy* -type f -name "*.rs" -exec cat {} \; | wc -l \ No newline at end of file diff --git a/README.md b/README.md index 015abf0..363acf7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Implementation of the [negentropy](https://github.com/hoytech/negentropy) set-re The project is split up into many crates: * [**negentropy**](./negentropy/): Rust implementation of the negentropy set-reconciliation protocol -* [**negentropy-ffi**](./negentropy-ffi/): UniFFI bindings (Swift, Kotlin and Python) of the [negentropy](./negentropy/) crate (TODO) +* [**negentropy-ffi**](./negentropy-ffi/): UniFFI bindings (Swift, Kotlin and Python) of the [negentropy](./negentropy/) crate ## Flame Graph and perf diff --git a/negentropy-ffi/.gitignore b/negentropy-ffi/.gitignore new file mode 100644 index 0000000..0171e15 --- /dev/null +++ b/negentropy-ffi/.gitignore @@ -0,0 +1,2 @@ +target/ +ffi/ \ No newline at end of file diff --git a/negentropy-ffi/Cargo.lock b/negentropy-ffi/Cargo.lock new file mode 100644 index 0000000..d1446ee --- /dev/null +++ b/negentropy-ffi/Cargo.lock @@ -0,0 +1,756 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a0fc7dcf8bd4ead96b1d36b41df47c14beedf7b0301fc543d8f2384e66a2ec0" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c268a96e01a4c47c8c5c2472aaa570707e006a875ea63e819f75474ceedaf7b4" +dependencies = [ + "nom", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "basic-toml" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "fs-err" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "goblin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "negentropy" +version = "0.3.1" + +[[package]] +name = "negentropy-ffi" +version = "0.1.0" +dependencies = [ + "negentropy", + "parking_lot", + "uniffi", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uniffi" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e835154c561cd75f253008093a908c06fb1f14327afb0ffea88eac72e534cc0" +dependencies = [ + "anyhow", + "camino", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f91fdcd44de3aab35847bf80485f412879dcdd92b5140ee67f948e5eed750e" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "clap", + "fs-err", + "glob", + "goblin", + "heck", + "once_cell", + "paste", + "serde", + "serde_json", + "toml", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + +[[package]] +name = "uniffi_build" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b20f693fb51c21a21b9816bed5522f0231cc769d8ba38821a05ab7d39dad51d" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1b354a9bd654cc6547d461ccd60a10eb6c7473178f12d8ff91cf4340ae947e8" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "uniffi_core" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32793120650ceda4f4e0d8eacd784c1a736834b2cca7b12e2550d3a190553af4" +dependencies = [ + "anyhow", + "bytes", + "camino", + "cargo_metadata", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65987b46a026ab1dfff218963d34c45375355dd6f1995618262e1e038507ba3" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", + "uniffi_build", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f815bba89a6585954c089c53a775d166c0334c907be0e462bf0f0ac0494656e7" +dependencies = [ + "anyhow", + "bytes", + "serde", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1048d7c54816dc27ed4041fe952d42c7cb88e711cf3299e36ee70df7692c4a39" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "weedle2" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" +dependencies = [ + "nom", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/negentropy-ffi/Cargo.toml b/negentropy-ffi/Cargo.toml new file mode 100644 index 0000000..3ab1569 --- /dev/null +++ b/negentropy-ffi/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "negentropy-ffi" +version = "0.1.0" +edition = "2021" +authors = ["Yuki Kishimoto "] +publish = false + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[lib] +name = "negentropy_ffi" +crate-type = ["lib", "cdylib", "staticlib"] + +[[bin]] +name = "uniffi-bindgen" +path = "uniffi-bindgen.rs" + +[dependencies] +negentropy = { path = "../negentropy" } +parking_lot = "0.12" +uniffi = { version = "0.24", features = ["cli"] } + +[build-dependencies] +uniffi = { version = "0.24", features = ["build"] } + +[profile.release] +lto = true +codegen-units = 1 +panic = "abort" \ No newline at end of file diff --git a/negentropy-ffi/Makefile b/negentropy-ffi/Makefile new file mode 100644 index 0000000..f20da82 --- /dev/null +++ b/negentropy-ffi/Makefile @@ -0,0 +1,15 @@ +precommit: + cargo fmt --all -- --config format_code_in_doc_comments=true + cargo build -p negentropy-ffi + cargo clippy -p negentropy-ffi + cargo test -p negentropy-ffi + +python: + rm -rf bindings-python/dist + pip install -r bindings-python/requirements.txt --break-system-packages + cargo build --release + cargo run --features=uniffi/cli --bin uniffi-bindgen generate src/negentropy.udl --language python --no-format -o bindings-python/src/negentropy/ + cp ../target/release/libnegentropy_ffi.so bindings-python/src/negentropy/ | true + cp ../target/release/libnegentropy_ffi.dylib bindings-python/src/negentropy/ | true + cd bindings-python && python setup.py --verbose bdist_wheel + pip install ./bindings-python/dist/negentropy*.whl --force-reinstall --break-system-packages diff --git a/negentropy-ffi/README.md b/negentropy-ffi/README.md new file mode 100644 index 0000000..d770083 --- /dev/null +++ b/negentropy-ffi/README.md @@ -0,0 +1,21 @@ +# Negentropy FFI + +## Build + +### Python + +For most users, we recommend using our official Python package: TODO. + +If you want to compile from source or need more options, read on. + +### Wheel + +#### Unix + +``` +make python +``` + +## License + +This project is distributed under the MIT software license - see the [LICENSE](../../LICENSE) file for details \ No newline at end of file diff --git a/negentropy-ffi/bindings-python/.gitignore b/negentropy-ffi/bindings-python/.gitignore new file mode 100644 index 0000000..504c404 --- /dev/null +++ b/negentropy-ffi/bindings-python/.gitignore @@ -0,0 +1,16 @@ +.tox/ +dist/ +negentropy.egg-info/ +__pycache__/ +libnegentropy_ffi.dylib +.idea/ +.DS_Store + +*.swp + +src/negentropy/negentropy.py +src/negentropy/*.so +*.whl +build/ + +testing-setup-py-simple-example.py diff --git a/negentropy-ffi/bindings-python/LICENSE b/negentropy-ffi/bindings-python/LICENSE new file mode 100644 index 0000000..2921678 --- /dev/null +++ b/negentropy-ffi/bindings-python/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Yuki Kishimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/negentropy-ffi/bindings-python/MANIFEST.in b/negentropy-ffi/bindings-python/MANIFEST.in new file mode 100644 index 0000000..4bbf227 --- /dev/null +++ b/negentropy-ffi/bindings-python/MANIFEST.in @@ -0,0 +1,3 @@ +include ./src/negentropy/libnegentropy_ffi.dylib +include ./src/negentropy/libnegentropy_ffi.so +include ./src/negentropy/negentropy_ffi.dll diff --git a/negentropy-ffi/bindings-python/README.md b/negentropy-ffi/bindings-python/README.md new file mode 100644 index 0000000..018b44a --- /dev/null +++ b/negentropy-ffi/bindings-python/README.md @@ -0,0 +1,13 @@ +# Negentropy - Python Package + +The Python language bindings for [negentropy](https://github.com/yukibtc/rust-negentropy). + +## Getting started + +```shell +pip install negentropy +``` + +## License + +This project is distributed under the MIT software license - see the [LICENSE](https://github.com/yukibtc/rust-negentropy/tree/master/LICENSE) file for details diff --git a/negentropy-ffi/bindings-python/examples/client.py b/negentropy-ffi/bindings-python/examples/client.py new file mode 100644 index 0000000..46a7173 --- /dev/null +++ b/negentropy-ffi/bindings-python/examples/client.py @@ -0,0 +1,32 @@ +from negentropy import Negentropy, Bytes + +# Client init +client = Negentropy(16, None) +client.add_item(0, Bytes.from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) +client.add_item(1, Bytes.from_hex("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")) +client.seal() +init_output = client.initiate() +print(f"Initiator Output: {init_output.as_hex()}") + +# Relay +relay = Negentropy(16, None) +relay.add_item(0, Bytes.from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) +relay.add_item(2, Bytes.from_hex("cccccccccccccccccccccccccccccccc")) +relay.add_item(3, Bytes.from_hex("11111111111111111111111111111111")) +relay.add_item(5, Bytes.from_hex("22222222222222222222222222222222")) +relay.add_item(10, Bytes.from_hex("33333333333333333333333333333333")) +relay.seal() +reconcile_output = relay.reconcile(init_output) +print(f"Reconcile Output: {reconcile_output.as_hex()}") + +# Client reconcile +reconcile_output_with_ids = client.reconcile_with_ids(reconcile_output) +print(f"Reconcile Output with IDs: {reconcile_output_with_ids.output}") + +print("Have IDs:") +for id in reconcile_output_with_ids.have_ids: + print(f"- {id.as_hex()}") + +print("Need IDs:") +for id in reconcile_output_with_ids.need_ids: + print(f"- {id.as_hex()}") \ No newline at end of file diff --git a/negentropy-ffi/bindings-python/pyproject.toml b/negentropy-ffi/bindings-python/pyproject.toml new file mode 100644 index 0000000..0c26a1d --- /dev/null +++ b/negentropy-ffi/bindings-python/pyproject.toml @@ -0,0 +1,5 @@ +[build-system] +requires = ["setuptools", "wheel"] + +[tool.pytest.ini_options] +pythonpath = ["."] \ No newline at end of file diff --git a/negentropy-ffi/bindings-python/requirements.txt b/negentropy-ffi/bindings-python/requirements.txt new file mode 100644 index 0000000..959ed44 --- /dev/null +++ b/negentropy-ffi/bindings-python/requirements.txt @@ -0,0 +1,4 @@ +semantic-version==2.9.0 +typing_extensions==4.0.1 +setuptools==67.4.0 +wheel==0.38.4 diff --git a/negentropy-ffi/bindings-python/setup.py b/negentropy-ffi/bindings-python/setup.py new file mode 100644 index 0000000..7ff6714 --- /dev/null +++ b/negentropy-ffi/bindings-python/setup.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +from setuptools import setup + +from pathlib import Path +this_directory = Path(__file__).parent +long_description = (this_directory / "README.md").read_text() + +setup( + name='negentropy', + version='0.0.1', + description="Negentropy set-reconciliation protocol.", + long_description=long_description, + long_description_content_type='text/markdown', + include_package_data = True, + zip_safe=False, + packages=['negentropy'], + package_dir={'negentropy': './src/negentropy'}, + url="https://github.com/yukibtc/rust-negentropy", + author="Yuki Kishimoto ", + license="MIT", + # This is required to ensure the library name includes the python version, abi, and platform tags + # See issue #350 for more information + has_ext_modules=lambda: True, +) diff --git a/negentropy-ffi/bindings-python/src/negentropy/__init__.py b/negentropy-ffi/bindings-python/src/negentropy/__init__.py new file mode 100644 index 0000000..f8adf26 --- /dev/null +++ b/negentropy-ffi/bindings-python/src/negentropy/__init__.py @@ -0,0 +1 @@ +from negentropy.negentropy import * diff --git a/negentropy-ffi/build.rs b/negentropy-ffi/build.rs new file mode 100644 index 0000000..deb0108 --- /dev/null +++ b/negentropy-ffi/build.rs @@ -0,0 +1,6 @@ +// Copyright (c) 2023 Yuki Kishimoto +// Distributed under the MIT software license + +fn main() { + uniffi::generate_scaffolding("./src/negentropy.udl").expect("Building the UDL file failed"); +} diff --git a/negentropy-ffi/src/bytes.rs b/negentropy-ffi/src/bytes.rs new file mode 100644 index 0000000..9dd7647 --- /dev/null +++ b/negentropy-ffi/src/bytes.rs @@ -0,0 +1,45 @@ +// Copyright (c) 2023 Yuki Kishimoto +// Distributed under the MIT software license + +use core::ops::Deref; + +use crate::error::Result; + +pub struct Bytes { + inner: negentropy::Bytes, +} + +impl Deref for Bytes { + type Target = negentropy::Bytes; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl From for Bytes { + fn from(inner: negentropy::Bytes) -> Self { + Self { inner } + } +} + +impl Bytes { + pub fn new(bytes: Vec) -> Self { + Self { + inner: negentropy::Bytes::new(bytes), + } + } + + pub fn from_hex(data: String) -> Result { + Ok(Self { + inner: negentropy::Bytes::from_hex(data)?, + }) + } + + pub fn as_hex(&self) -> String { + self.inner.as_hex() + } + + pub fn as_bytes(&self) -> Vec { + self.inner.as_bytes().to_vec() + } +} diff --git a/negentropy-ffi/src/error.rs b/negentropy-ffi/src/error.rs new file mode 100644 index 0000000..d36f66e --- /dev/null +++ b/negentropy-ffi/src/error.rs @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Yuki Kishimoto +// Distributed under the MIT software license + +use core::fmt; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum NegentropyError { + Generic { err: String }, +} + +impl fmt::Display for NegentropyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Generic { err } => write!(f, "{err}"), + } + } +} + +impl From for NegentropyError { + fn from(e: negentropy::Error) -> Self { + Self::Generic { err: e.to_string() } + } +} diff --git a/negentropy-ffi/src/lib.rs b/negentropy-ffi/src/lib.rs new file mode 100644 index 0000000..9793c49 --- /dev/null +++ b/negentropy-ffi/src/lib.rs @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Yuki Kishimoto +// Distributed under the MIT software license + +use std::ops::Deref; +use std::sync::Arc; + +use parking_lot::RwLock; + +mod bytes; +mod error; + +pub use self::bytes::Bytes; +pub use self::error::NegentropyError; +use self::error::Result; + +pub struct ReconcileWithIds { + pub have_ids: Vec>, + pub need_ids: Vec>, + pub output: Option>, +} + +pub struct Negentropy { + inner: RwLock, +} + +impl Negentropy { + pub fn new(id_size: u8, frame_size_limit: Option) -> Result { + Ok(Self { + inner: RwLock::new(negentropy::Negentropy::new( + id_size as usize, + frame_size_limit, + )?), + }) + } + + pub fn id_size(&self) -> u64 { + self.inner.read().id_size() as u64 + } + + /// Check if current instance it's an initiator + pub fn is_initiator(&self) -> bool { + self.inner.read().is_initiator() + } + + /// Check if sealed + pub fn is_sealed(&self) -> bool { + self.inner.read().is_sealed() + } + + /// Check if need to continue + pub fn continuation_needed(&self) -> bool { + self.inner.read().continuation_needed() + } + + pub fn add_item(&self, created_at: u64, id: Arc) -> Result<()> { + let mut negentropy = self.inner.write(); + Ok(negentropy.add_item(created_at, id.as_ref().deref().clone())?) + } + + pub fn seal(&self) -> Result<()> { + let mut negentropy = self.inner.write(); + Ok(negentropy.seal()?) + } + + /// Initiate reconciliation set + pub fn initiate(&self) -> Result> { + let mut negentropy = self.inner.write(); + Ok(Arc::new(negentropy.initiate()?.into())) + } + + pub fn reconcile(&self, query: Arc) -> Result> { + let mut negentropy = self.inner.write(); + Ok(Arc::new( + negentropy.reconcile(query.as_ref().deref())?.into(), + )) + } + + pub fn reconcile_with_ids(&self, query: Arc) -> Result { + let mut negentropy = self.inner.write(); + let mut have_ids: Vec = Vec::new(); + let mut need_ids: Vec = Vec::new(); + let output: Option = + negentropy.reconcile_with_ids(query.as_ref().deref(), &mut have_ids, &mut need_ids)?; + Ok(ReconcileWithIds { + have_ids: have_ids.into_iter().map(|id| Arc::new(id.into())).collect(), + need_ids: need_ids.into_iter().map(|id| Arc::new(id.into())).collect(), + output: output.map(|o| Arc::new(o.into())), + }) + } +} + +// UDL +uniffi::include_scaffolding!("negentropy"); diff --git a/negentropy-ffi/src/negentropy.udl b/negentropy-ffi/src/negentropy.udl new file mode 100644 index 0000000..e8566bb --- /dev/null +++ b/negentropy-ffi/src/negentropy.udl @@ -0,0 +1,42 @@ +// Copyright (c) 2022-2023 Yuki Kishimoto +// Distributed under the MIT software license + +namespace negentropy {}; + +[Error] +interface NegentropyError { + Generic(string err); +}; + +interface Bytes { + constructor(bytes bytes); + [Throws=NegentropyError, Name=from_hex] + constructor(string data); + string as_hex(); + bytes as_bytes(); +}; + +dictionary ReconcileWithIds { + sequence have_ids; + sequence need_ids; + Bytes? output; +}; + +interface Negentropy { + [Throws=NegentropyError] + constructor(u8 id_size, u64? frame_size_limit); + u64 id_size(); + boolean is_initiator(); + boolean is_sealed(); + boolean continuation_needed(); + [Throws=NegentropyError] + void add_item(u64 created_at, Bytes id); + [Throws=NegentropyError] + void seal(); + [Throws=NegentropyError] + Bytes initiate(); + [Throws=NegentropyError] + Bytes reconcile(Bytes query); + [Throws=NegentropyError] + ReconcileWithIds reconcile_with_ids(Bytes query); +}; \ No newline at end of file diff --git a/negentropy-ffi/uniffi-bindgen.rs b/negentropy-ffi/uniffi-bindgen.rs new file mode 100644 index 0000000..5432ce3 --- /dev/null +++ b/negentropy-ffi/uniffi-bindgen.rs @@ -0,0 +1,6 @@ +// Copyright (c) 2023 Yuki Kishimoto +// Distributed under the MIT software license + +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/negentropy-ffi/uniffi.toml b/negentropy-ffi/uniffi.toml new file mode 100644 index 0000000..1bcb72d --- /dev/null +++ b/negentropy-ffi/uniffi.toml @@ -0,0 +1,10 @@ +[bindings.kotlin] +package_name = "negentropy" +cdylib_name = "negentropy_ffi" + +[bindings.swift] +ffi_module_filename = "negentropyFFI" +cdylib_name = "negentropy_ffi" + +[bindings.python] +cdylib_name = "negentropy_ffi" \ No newline at end of file