diff --git a/.github/actions/android/action.yml b/.github/actions/android/action.yml index d124a9b4..6fdfee70 100644 --- a/.github/actions/android/action.yml +++ b/.github/actions/android/action.yml @@ -25,8 +25,8 @@ runs: - name: Setup shell: bash run: | - rustup toolchain install nightly-2025-04-15-x86_64-unknown-linux-gnu - rustup component add rust-src --toolchain nightly-2025-04-15-x86_64-unknown-linux-gnu + rustup toolchain install nightly-2025-10-31-x86_64-unknown-linux-gnu + rustup component add rust-src --toolchain nightly-2025-10-31-x86_64-unknown-linux-gnu rustup target add \ aarch64-linux-android \ armv7-linux-androideabi \ diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml index 12fed296..60ba7eb1 100644 --- a/.github/actions/linux/action.yml +++ b/.github/actions/linux/action.yml @@ -7,7 +7,7 @@ runs: - name: Install Rust Nightly uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly-2025-04-15 + toolchain: nightly-2025-10-31 components: rust-src targets: aarch64-unknown-linux-gnu,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu,riscv64gc-unknown-linux-gnu,armv7-unknown-linux-gnueabihf diff --git a/.github/actions/macos/action.yml b/.github/actions/macos/action.yml index efb643e5..b7a5be21 100644 --- a/.github/actions/macos/action.yml +++ b/.github/actions/macos/action.yml @@ -7,7 +7,7 @@ runs: - name: Install Rust Nightly uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly-2025-04-15 + toolchain: nightly-2025-10-31 components: rust-src targets: x86_64-apple-darwin,aarch64-apple-darwin diff --git a/.github/actions/wasm/action.yml b/.github/actions/wasm/action.yml index 723bf3aa..475685fb 100644 --- a/.github/actions/wasm/action.yml +++ b/.github/actions/wasm/action.yml @@ -7,7 +7,7 @@ runs: - name: Install Rust Nightly uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly-2025-04-15 + toolchain: nightly-2025-10-31 components: rust-src - name: Setup emsdk diff --git a/.github/actions/windows/action.yml b/.github/actions/windows/action.yml index f94d05e0..9864f1d9 100644 --- a/.github/actions/windows/action.yml +++ b/.github/actions/windows/action.yml @@ -7,7 +7,7 @@ runs: - name: Install Rust Nightly uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly-2025-04-15 + toolchain: nightly-2025-10-31 components: rust-src targets: x86_64-pc-windows-msvc,aarch64-pc-windows-msvc,i686-pc-windows-msvc diff --git a/.github/actions/xcframework/action.yml b/.github/actions/xcframework/action.yml index 90d0ad22..a303c7d1 100644 --- a/.github/actions/xcframework/action.yml +++ b/.github/actions/xcframework/action.yml @@ -7,8 +7,8 @@ runs: - name: Setup shell: bash run: | - rustup toolchain install nightly-2025-04-15-aarch64-apple-darwin - rustup component add rust-src --toolchain nightly-2025-04-15-aarch64-apple-darwin + rustup toolchain install nightly-2025-10-31-aarch64-apple-darwin + rustup component add rust-src --toolchain nightly-2025-10-31-aarch64-apple-darwin rustup target add \ x86_64-apple-darwin \ aarch64-apple-darwin \ diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 718c3312..e6ef5e73 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -94,7 +94,7 @@ jobs: - name: Install Rust Nightly uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly-2025-04-15 + toolchain: nightly-2025-10-31 components: rust-src,rustfmt,clippy - name: Check formatting @@ -102,9 +102,6 @@ jobs: - name: Build run: | - # Need a debug build for the dart tests - cargo build -p powersync_loadable - cargo build -p powersync_loadable --release cargo build -p powersync_core --release --features static cargo build -p powersync_sqlite --release @@ -189,6 +186,40 @@ jobs: CORE_TEST_SQLITE=.dart_tool/sqlite3/latest/libsqlite3.dylib dart test -P skip_slow CORE_TEST_SQLITE=.dart_tool/sqlite3/minimum/libsqlite3.dylib dart test -P skip_slow + build_stable_rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: dart-lang/setup-dart@v1 + - name: Install Rust Stable + uses: dtolnay/rust-toolchain@stable + + - uses: actions/cache@v4 + id: sqlite_build + with: + path: dart/.dart_tool/sqlite3/ + key: ${{ matrix.os }}-${{ hashFiles('dart/tool/') }} + + - name: Setup Dart tests + working-directory: dart + run: | + dart pub get + dart run tool/download_sqlite3.dart + dart analyze + + - name: Compile with stable Rust + run: | + cargo +stable build -p powersync_loadable + + - name: Dart tests with stable Rust + working-directory: dart + run: | + CORE_TEST_SQLITE=.dart_tool/sqlite3/latest/libsqlite3.so dart test + CORE_TEST_SQLITE=.dart_tool/sqlite3/minimum/libsqlite3.so dart test + valgrind: name: Testing with Valgrind on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -201,6 +232,11 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: Install Rust Nightly + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly-2025-10-31 + components: rust-src - name: Install valgrind run: sudo apt update && sudo apt install -y valgrind diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 65720280..05e30350 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -83,6 +83,8 @@ fun Exec.rustCompilation(project: String, output: String? = null) { "-Zbuild-std", "-p", project, + "--features", + "nightly" ) } diff --git a/crates/core/src/bson/de.rs b/crates/core/src/bson/de.rs index c1f6188c..6073d114 100644 --- a/crates/core/src/bson/de.rs +++ b/crates/core/src/bson/de.rs @@ -1,5 +1,3 @@ -use core::assert_matches::debug_assert_matches; - use serde::{ de::{ self, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, VariantAccess, @@ -250,7 +248,10 @@ impl<'de> SeqAccess<'de> for Deserializer<'de> { } // Skip name - debug_assert_matches!(self.position, DeserializerPosition::BeforeName { .. }); + assert!(matches!( + self.position, + DeserializerPosition::BeforeName { .. } + )); self.prepare_to_read(true)?; // And deserialize value! diff --git a/crates/core/src/bson/mod.rs b/crates/core/src/bson/mod.rs index 7d276202..bbf77a40 100644 --- a/crates/core/src/bson/mod.rs +++ b/crates/core/src/bson/mod.rs @@ -16,7 +16,6 @@ pub fn from_bytes<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result Result<(), ResultCode> { #[cfg(test)] mod test { - use core::assert_matches::assert_matches; use super::remove_duplicate_key_encoding; fn assert_unaffected(source: &str) { - assert_matches!(remove_duplicate_key_encoding(source), None); + assert!(matches!(remove_duplicate_key_encoding(source), None)); } #[test] diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index b9e662db..92867e53 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,9 +1,4 @@ #![no_std] -#![feature(btree_set_entry)] -#![feature(assert_matches)] -#![feature(strict_overflow_ops)] -#![feature(vec_into_raw_parts)] - extern crate alloc; use core::ffi::{c_char, c_int}; diff --git a/crates/core/src/state.rs b/crates/core/src/state.rs index 72f68b3e..9a844909 100644 --- a/crates/core/src/state.rs +++ b/crates/core/src/state.rs @@ -31,7 +31,7 @@ impl DatabaseState { Self::default() } - pub fn view_schema(&self) -> Option> { + pub fn view_schema(&'_ self) -> Option> { let schema_ref = self.schema.borrow(); if schema_ref.is_none() { None @@ -63,7 +63,12 @@ impl DatabaseState { pub fn track_update(&self, tbl: &str) { let mut set = self.pending_updates.borrow_mut(); - set.get_or_insert_with(tbl, str::to_string); + // TODO: Use set.get_or_insert_with(tbl, str::to_string) after btree_set_entry is stable, + // https://github.com/rust-lang/rust/issues/133549 + if !set.contains(tbl) { + // Check whether the set contains the entry first to avoid an unconditional allocation. + set.insert(tbl.to_string()); + } } pub fn track_rollback(&self) { diff --git a/crates/core/src/sync/line.rs b/crates/core/src/sync/line.rs index f61de748..e4853b33 100644 --- a/crates/core/src/sync/line.rs +++ b/crates/core/src/sync/line.rs @@ -325,27 +325,26 @@ impl<'a, 'de: 'a> Deserialize<'de> for OplogData<'a> { #[cfg(test)] mod tests { - use core::assert_matches::assert_matches; use alloc::string::ToString; use super::*; - fn deserialize(source: &str) -> SyncLine { + fn deserialize(source: &'_ str) -> SyncLine<'_> { serde_json::from_str(source).expect("Should have deserialized") } #[test] fn parse_token_expires_in() { - assert_matches!( + assert!(matches!( deserialize(r#"{"token_expires_in": 123}"#), SyncLine::KeepAlive(TokenExpiresIn(123)) - ); + )); } #[test] fn parse_checkpoint() { - assert_matches!( + assert!(matches!( deserialize(r#"{"checkpoint": {"last_op_id": "10", "buckets": []}}"#), SyncLine::Checkpoint(Checkpoint { last_op_id: 10, @@ -353,7 +352,7 @@ mod tests { buckets: _, streams: _, }) - ); + )); let SyncLine::Checkpoint(checkpoint) = deserialize( r#"{"checkpoint": {"last_op_id": "10", "buckets": [{"bucket": "a", "checksum": 10}]}}"#, @@ -379,7 +378,7 @@ mod tests { assert_eq!(bucket.checksum, 10u32.into()); assert_eq!(bucket.priority, Some(BucketPriority { number: 1 })); - assert_matches!( + assert!(matches!( deserialize( r#"{"checkpoint":{"write_checkpoint":null,"last_op_id":"1","buckets":[{"bucket":"a","checksum":0,"priority":3,"count":1}]}}"# ), @@ -389,7 +388,7 @@ mod tests { buckets: _, streams: _, }) - ); + )); } #[test] @@ -426,23 +425,23 @@ mod tests { #[test] fn parse_checkpoint_complete() { - assert_matches!( + assert!(matches!( deserialize(r#"{"checkpoint_complete": {"last_op_id": "10"}}"#), SyncLine::CheckpointComplete(CheckpointComplete { // last_op_id: 10 }) - ); + )); } #[test] fn parse_checkpoint_partially_complete() { - assert_matches!( + assert!(matches!( deserialize(r#"{"partial_checkpoint_complete": {"last_op_id": "10", "priority": 1}}"#), SyncLine::CheckpointPartiallyComplete(CheckpointPartiallyComplete { //last_op_id: 10, priority: BucketPriority { number: 1 } }) - ); + )); } #[test] @@ -463,7 +462,7 @@ mod tests { assert_eq!(data.data.len(), 1); let entry = &data.data[0]; assert_eq!(entry.checksum, 10u32.into()); - assert_matches!( + assert!(matches!( &data.data[0], OplogEntry { checksum: _, @@ -474,13 +473,19 @@ mod tests { subkey: None, data: _, } - ); + )); } #[test] fn parse_unknown() { - assert_matches!(deserialize("{\"foo\": {}}"), SyncLine::UnknownSyncLine); - assert_matches!(deserialize("{\"foo\": 123}"), SyncLine::UnknownSyncLine); + assert!(matches!( + deserialize("{\"foo\": {}}"), + SyncLine::UnknownSyncLine + )); + assert!(matches!( + deserialize("{\"foo\": 123}"), + SyncLine::UnknownSyncLine + )); } #[test] diff --git a/crates/core/src/sync/storage_adapter.rs b/crates/core/src/sync/storage_adapter.rs index 2e1174cd..8bcc2ac1 100644 --- a/crates/core/src/sync/storage_adapter.rs +++ b/crates/core/src/sync/storage_adapter.rs @@ -1,4 +1,4 @@ -use core::{assert_matches::debug_assert_matches, fmt::Display}; +use core::fmt::Display; use alloc::{rc::Rc, string::ToString, vec::Vec}; use serde::Serialize; @@ -140,7 +140,7 @@ impl StorageAdapter { Ok(()) } - pub fn step_progress(&self) -> Result, ResultCode> { + pub fn step_progress(&'_ self) -> Result>, ResultCode> { if self.progress_stmt.step()? == ResultCode::ROW { let bucket = self.progress_stmt.column_text(0)?; let count_at_last = self.progress_stmt.column_int64(1); @@ -181,7 +181,7 @@ impl StorageAdapter { .into_db_result(self.db)?; bucket_statement.bind_text(1, bucket, sqlite::Destructor::STATIC)?; let res = bucket_statement.step()?; - debug_assert_matches!(res, ResultCode::ROW); + debug_assert_eq!(res, ResultCode::ROW); let bucket_id = bucket_statement.column_int64(0); let last_applied_op = bucket_statement.column_int64(1); diff --git a/crates/core/src/sync/sync_status.rs b/crates/core/src/sync/sync_status.rs index 0a5194b6..9e69cdfb 100644 --- a/crates/core/src/sync/sync_status.rs +++ b/crates/core/src/sync/sync_status.rs @@ -427,8 +427,11 @@ impl ActiveStreamSubscription { } pub fn mark_associated_with_bucket(&mut self, bucket: &OwnedBucketChecksum) { - self.associated_buckets - .get_or_insert_with(&bucket.bucket, |key| key.clone()); + // This avoids an allocation if the bucket is already tracked. TODO: Use get_or_insert_with + // after https://github.com/rust-lang/rust/issues/133549 is stable. + if !self.associated_buckets.contains(&bucket.bucket) { + self.associated_buckets.insert(bucket.bucket.clone()); + } self.priority = Some(match self.priority { None => bucket.priority, diff --git a/crates/core/src/sync_local.rs b/crates/core/src/sync_local.rs index fd0728ff..60f9c5d4 100644 --- a/crates/core/src/sync_local.rs +++ b/crates/core/src/sync_local.rs @@ -483,16 +483,16 @@ impl<'a> RawTableWithCachedStatements<'a> { } fn put_statement( - &mut self, + &'_ mut self, db: *mut sqlite::sqlite3, - ) -> Result<&PreparedPendingStatement, PowerSyncError> { + ) -> Result<&'_ PreparedPendingStatement<'_>, PowerSyncError> { Self::prepare_lazily(db, &mut self.cached_put, &self.definition.put) } fn delete_statement( - &mut self, + &'_ mut self, db: *mut sqlite::sqlite3, - ) -> Result<&PreparedPendingStatement, PowerSyncError> { + ) -> Result<&'_ PreparedPendingStatement<'_>, PowerSyncError> { Self::prepare_lazily(db, &mut self.cached_delete, &self.definition.delete) } } diff --git a/crates/loadable/Cargo.toml b/crates/loadable/Cargo.toml index de22f9f1..2558583c 100644 --- a/crates/loadable/Cargo.toml +++ b/crates/loadable/Cargo.toml @@ -21,4 +21,5 @@ default-features = false features = [] [features] +nightly = [] default = ["powersync_core/loadable_extension", "sqlite_nostd/loadable_extension", "powersync_core/getrandom"] diff --git a/crates/loadable/src/lib.rs b/crates/loadable/src/lib.rs index 9e5a9de8..c5c8cc64 100644 --- a/crates/loadable/src/lib.rs +++ b/crates/loadable/src/lib.rs @@ -1,8 +1,7 @@ #![no_std] -#![feature(vec_into_raw_parts)] -#![feature(core_intrinsics)] #![allow(internal_features)] -#![feature(lang_items)] +#![cfg_attr(feature = "nightly", feature(core_intrinsics))] +#![cfg_attr(feature = "nightly", feature(lang_items))] extern crate alloc; @@ -20,12 +19,30 @@ static ALLOCATOR: SQLite3Allocator = SQLite3Allocator {}; // Custom Panic handler for WASM and other no_std builds #[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - core::intrinsics::abort() -} +mod panic_handler { + #[cfg(feature = "nightly")] + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + core::intrinsics::abort() + } -#[cfg(not(target_family = "wasm"))] -#[cfg(not(test))] -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} + #[cfg(not(feature = "nightly"))] + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } + + #[cfg(not(target_family = "wasm"))] + #[cfg(feature = "nightly")] + #[lang = "eh_personality"] + extern "C" fn eh_personality() {} + + #[cfg(not(target_family = "wasm"))] + #[cfg(not(feature = "nightly"))] + #[unsafe(no_mangle)] + extern "C" fn rust_eh_personality() { + // This avoids missing _rust_eh_personality symbol errors. + // This isn't used for any builds we distribute, but it's heplful to compile the library + // with stable Rust, which we do for testing. + } +} diff --git a/crates/static/Cargo.toml b/crates/static/Cargo.toml index cc7e0f3e..d1991f72 100644 --- a/crates/static/Cargo.toml +++ b/crates/static/Cargo.toml @@ -21,4 +21,5 @@ default-features = false features = [] [features] +nightly = [] default = ["powersync_core/static", "powersync_core/omit_load_extension", "sqlite_nostd/omit_load_extension"] diff --git a/crates/static/src/lib.rs b/crates/static/src/lib.rs index 1d46244d..b889535c 100644 --- a/crates/static/src/lib.rs +++ b/crates/static/src/lib.rs @@ -1,8 +1,6 @@ #![no_std] -#![feature(vec_into_raw_parts)] -#![feature(core_intrinsics)] #![allow(internal_features)] -#![feature(lang_items)] +#![cfg_attr(feature = "nightly", feature(core_intrinsics))] extern crate alloc; @@ -20,7 +18,16 @@ static ALLOCATOR: SQLite3Allocator = SQLite3Allocator {}; // Custom Panic handler for WASM and other no_std builds #[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - core::intrinsics::abort() +mod panic_handler { + #[cfg(feature = "nightly")] + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + core::intrinsics::abort() + } + + #[cfg(not(feature = "nightly"))] + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d547223..af7304e5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly-2025-04-15" +channel = "nightly-2025-10-31" diff --git a/tool/build_linux.sh b/tool/build_linux.sh index fd9f3249..2b98b259 100755 --- a/tool/build_linux.sh +++ b/tool/build_linux.sh @@ -5,8 +5,8 @@ function compile() { local triple=$1 local suffix=$2 - cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --release --target $triple - cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --release --target $triple + cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --features nightly --release --target $triple + cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --features nightly --release --target $triple mv "target/$triple/release/libpowersync.so" "libpowersync_$suffix.linux.so" mv "target/$triple/release/libpowersync.a" "libpowersync_$suffix.linux.a" diff --git a/tool/build_macos.sh b/tool/build_macos.sh index 7aca8344..3d7a96a0 100755 --- a/tool/build_macos.sh +++ b/tool/build_macos.sh @@ -6,8 +6,8 @@ function compile() { local suffix=$2 local os=$3 - cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --release --target $triple - cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --release --target $triple + cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --features nightly --release --target $triple + cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --features nightly --release --target $triple mv "target/$triple/release/libpowersync.dylib" "libpowersync_$suffix.$os.dylib" mv "target/$triple/release/libpowersync.a" "libpowersync_$suffix.$os.a" diff --git a/tool/build_wasm.sh b/tool/build_wasm.sh index f40d8edc..35bf8bb6 100755 --- a/tool/build_wasm.sh +++ b/tool/build_wasm.sh @@ -9,7 +9,7 @@ RUSTFLAGS="-C link-arg=-sSIDE_MODULE=2" \ -p powersync_loadable \ --profile wasm \ --no-default-features \ - --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension" \ + --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension nightly" \ -Z build-std=panic_abort,core,alloc \ --target wasm32-unknown-emscripten @@ -22,7 +22,7 @@ RUSTFLAGS="-C link-arg=-sSIDE_MODULE=2 -C link-arg=-sASYNCIFY=1 -C link-arg=-sJS -p powersync_loadable \ --profile wasm_asyncify \ --no-default-features \ - --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension" \ + --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension nightly" \ -Z build-std=panic_abort,core,alloc \ --target wasm32-unknown-emscripten @@ -37,7 +37,7 @@ cargo build \ -p powersync_loadable \ --profile wasm \ --no-default-features \ - --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension" \ + --features "powersync_core/static powersync_core/omit_load_extension sqlite_nostd/omit_load_extension nightly" \ -Z build-std=panic_abort,core,alloc \ --target wasm32-wasip1 diff --git a/tool/build_windows.sh b/tool/build_windows.sh index 0e3c6fcc..17546a73 100755 --- a/tool/build_windows.sh +++ b/tool/build_windows.sh @@ -5,8 +5,8 @@ function compile() { local triple=$1 local suffix=$2 - cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --release --target $triple - cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --release --target $triple + cargo build -p powersync_loadable -Z build-std=panic_abort,core,alloc --features=nightly --release --target $triple + cargo build -p powersync_static -Z build-std=panic_abort,core,alloc --features=nightly --release --target $triple mv "target/$triple/release/powersync.dll" "powersync_$suffix.dll" mv "target/$triple/release/powersync.lib" "powersync_$suffix.lib" diff --git a/tool/build_xcframework.sh b/tool/build_xcframework.sh index 2d39529e..ab0bf398 100755 --- a/tool/build_xcframework.sh +++ b/tool/build_xcframework.sh @@ -187,10 +187,11 @@ for TARGET in ${TARGETS[@]}; do cargo build \ -p powersync_static \ --profile release_apple \ + --features nightly \ --target $TARGET \ -Zbuild-std else - cargo build -p powersync_loadable --profile release_apple --target $TARGET -Zbuild-std + cargo build -p powersync_loadable --profile release_apple --features nightly --target $TARGET -Zbuild-std fi done