# `rust/` — strawcore: Rust YouTube core for Straw Phase **U-** of the Straw build. Goal: replace the Java NewPipeExtractor dependency with a Rust core (rustypipe + tokio + reqwest), exposed to the Kotlin/Compose UI via [UniFFI](https://mozilla.github.io/uniffi-rs/). Compose UI stays in Kotlin — only the YouTube/Innertube fetching layer moves to Rust. ## Phases | Phase | What | |---|---| | **U-1** | Toolchain + UniFFI smoke test (`hello_from_rust`) round-tripping through JNA. No real APIs yet. | | **U-2** | rustypipe search. `SearchViewModel` calls the Rust core. | | **U-3** | rustypipe streamInfo + streams. `VideoDetailViewModel` + `PlayerViewModel` use it. | | **U-4** | rustypipe channel + tabs. `ChannelViewModel` + `SubscriptionFeedViewModel`. | | **U-5** | Rip NewPipeExtractor Java dep. Measure APK + cold-fetch latency before/after. | | **U-6** *(stretch)* | SponsorBlock + RYD HTTP through reqwest + tokio in the same lib. | ## Build chain ``` Build container (Sulkta uses one; any toolchain matching this layout works) ├── rustup stable (target add: aarch64-linux-android, armv7-linux-androideabi, │ x86_64-linux-android, i686-linux-android) ├── cargo-ndk (cross-compile helper) ├── android-sdk (ANDROID_HOME, sdkmanager, build-tools, platforms) └── android-ndk (ANDROID_NDK_HOME, r27c LTS) Gradle (strawApp/build.gradle.kts) ├── cargoBuild Exec task → cargo ndk -t ... -o jniLibs/ build --release ├── uniffiBindgen Exec task → cargo run --bin uniffi-bindgen ... --library libstrawcore.so └── source-set wiring generated Kotlin lands in strawApp/src/main/java/uniffi/strawcore/ Runtime (StrawApp.onCreate) ├── System.loadLibrary("strawcore") └── uniffi.strawcore.initLogging() ``` ## Why UniFFI (and not raw JNI / JNA bindings) - Hand-written JNI: tedious, error-prone, every type change is two files (Kotlin + Rust) that must stay in sync. - Raw JNA: better, but you still hand-write the Kotlin side and worry about string ownership. - UniFFI: write Rust, annotate with `#[uniffi::export]`, get a Kotlin shim generated. Strings, structs, enums, Result types, `async` functions all cross the boundary transparently. The runtime is JNA under the hood. ## When in doubt - `cargo check -p strawcore --target aarch64-linux-android` — fast iteration. - `cargo run --bin uniffi-bindgen -- generate ...` — regenerate Kotlin bindings. - `adb logcat -s strawcore` — Rust `log::info!()` lands here. - `aapt dump badging strawApp/build/outputs/apk/debug/strawApp-debug.apk` — inspect what ABIs/native-libs the APK carries.