Add C-ABI iOS/Swift FFI wrapper crate (dithering only)#56
Open
davelee98 wants to merge 3 commits into
Open
Conversation
Adds `packages/rust/ios`, a thin C-ABI wrapper around `epaper-dithering-core` so the OpenDisplay iOS app can call the same OKLab dithering as the website/Python instead of its divergent sRGB-Euclidean Swift reimplementation. Scope is deliberately minimal — matching + error diffusion only. Tone/ gamut/exposure/saturation pre-processing is NOT surfaced: the app keeps its own tone-compression pass in Swift for now and hands us already-pre-processed pixels, so we run at DitherConfig defaults. Design (locked for iOS-only): - Plain C ABI (`ed_dither`, `ed_abi_version`), no UniFFI. - Caller-allocated output: output length is deterministically width*height, so Swift allocates; nothing crosses the boundary to free. - Indices returned in the caller's palette order, so the app's existing wire-format packing needs no remap. - Panics can't cross FFI (catch_unwind -> ED_ERR_PANIC); errors are negative status codes. Wiring: - staticlib+cdylib+rlib crate, excluded from the workspace (like `wasm`) so Linux `cargo build --workspace` and the Python sdist vendoring are unaffected. - build-xcframework.sh produces EpaperDithering.xcframework (device arm64 + simulator arm64/x86_64) — the only Xcode-gated step. - ios-test.yml runs the FFI unit/integration tests on the HOST target (Ubuntu, no Xcode) on every PR; includes a test asserting byte-for-byte parity with calling core::dither directly. Not built/verified locally: no Rust toolchain on the authoring machine. CI (ios-test.yml) builds and tests the FFI; the XCFramework must be built on a Mac with Rust + iOS targets. App-side ImageProcessor integration is a follow-up PR in the app repo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KCmHoU5FHgL4Sec6EFfLpy
Contributor
Author
|
Retargeting to davelee98/epaper-dithering (origin) as intended. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Matches the idiom already used in the wasm crate. Verified locally: cargo test (6 pass, incl. core::dither byte-parity), cargo clippy clean, and build-xcframework.sh produces a valid XCFramework (device arm64 + simulator arm64/x86_64) exporting ed_dither / ed_abi_version. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KCmHoU5FHgL4Sec6EFfLpy
The XCFramework is vendored into the app repo's git, so keep the static archives lean: release profile now uses lto + codegen-units=1 + strip="debuginfo", and build-xcframework.sh runs `strip -S -x` on each archive (retaining the ed_dither/ed_abi_version globals needed for linking). Cuts the framework from ~54MB to ~36MB. panic stays "unwind" — the FFI relies on catch_unwind. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KCmHoU5FHgL4Sec6EFfLpy
Contributor
Author
|
This is so I can re-use the Rust core in the iOS app. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
packages/rust/ios— a thin C-ABI wrapper aroundepaper-dithering-coreso the OpenDisplay iOS app can call the same OKLab dithering as the website / Python, replacing a divergent sRGB-Euclidean Swift reimplementation. Sibling of the existingwasmcrate.Scope (deliberately minimal)
Matching + error diffusion only. Tone / gamut / exposure / saturation pre-processing is not surfaced — the app keeps its tone pass in Swift and hands us pre-processed pixels, so we run at
DitherConfigdefaults.API (
include/epaper_dithering.h)ed_dither(...) -> int32_t— dither flat sRGB → palette indices.ed_abi_version() -> uint32_t.Design: plain C ABI (no UniFFI); caller-allocated output (length is deterministically
width*height, so nothing crosses the boundary to free); indices in the caller's palette order (lines up with the app's wire packing, no remap); panics can't cross FFI (catch_unwind→ status code).Wiring
staticlib+cdylib+rlibcrate, excluded from the workspace (likewasm) so Linuxcargo build --workspaceand the Python sdist vendoring (Packaging issues with pypi package #40) are unaffected.build-xcframework.sh→ device arm64 + simulator arm64/x86_64 XCFramework, stripped/LTO'd (~36 MB). The only Xcode-gated step..github/workflows/ios-test.yml— builds & tests the FFI on the host target (Ubuntu, no Xcode) every PR, including a byte-for-byte parity test againstcore::dither.Verified locally (Rust 1.97.1, Xcode 26.6)
cargo test→ 6/6;cargo clippy -- -D warnings→ clean;build-xcframework.sh→ valid XCFramework exportinged_dither/ed_abi_version. Already consumed by the OpenDisplay iOS app (vendored XCFramework), where its output matches the reference byte-for-byte on real photos.🤖 Generated with Claude Code