From 73ef09978cfd5bacbf0c2c2600ff6458af001247 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Jul 2026 10:20:42 +0000 Subject: [PATCH 1/2] build: increase MSRV to 1.95 --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 929f6f1043..9e2dcd1b5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ env: RUST_VERSION: 1.97.0 # Minimum Supported Rust Version - MSRV: 1.89.0 + MSRV: 1.95.0 jobs: lint_rust: diff --git a/Cargo.toml b/Cargo.toml index e4eba3b68d..20ff5f2f59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "deltachat" version = "2.54.0-dev" edition = "2024" license = "MPL-2.0" -rust-version = "1.89" +rust-version = "1.95" repository = "https://github.com/chatmail/core" [profile.dev] From da3f434143aa95ba82fad45a23332b5f3518df6b Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Jul 2026 01:54:27 +0000 Subject: [PATCH 2/2] chore: update rusqlite from 0.37 to 0.40 Largest change comes from removal of u64 and usize serialization in rusqlite 0.38.0. It is possible to enable it back with `fallible_uint` feature as suggested in https://github.com/rusqlite/rusqlite/pull/1732, but there is a good reason for this change as it may result in unexpected failures when trying to store u64 integers that don't fit in i64, so I don't enable it back. With this change conversions between i64 and u64 are explicit. Using less `usize` is generally good as its size differs on 32-bit platforms that are rarely tested but still supported and we have changes that reduce its usage such as 0defa117a0a302985c61fe211d1a6a948a06d4f6, 014d2ace76790a8484609a4a27fce53ba2fdaba3 etc. --- Cargo.lock | 116 +++++++++++++++++++++++++++--------------- Cargo.toml | 2 +- deny.toml | 3 ++ src/constants.rs | 2 +- src/net.rs | 2 +- src/receive_imf.rs | 8 ++- src/sql/migrations.rs | 6 +-- src/stats.rs | 6 +-- src/storage_usage.rs | 24 ++++++--- 9 files changed, 109 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5aafc78ab7..72667c9ca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2114,6 +2114,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2426,16 +2432,34 @@ checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash 0.2.0", ] [[package]] name = "hashlink" -version = "0.10.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "32069d97bb81e38fa67eab65e3393bf804bb85969f2bc06bf13f64aef5aba248" dependencies = [ - "hashbrown", + "hashbrown 0.17.1", ] [[package]] @@ -2969,7 +2993,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.4", ] [[package]] @@ -3286,11 +3310,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -3369,9 +3394,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.35.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +checksum = "f6c19a05435c21ac299d71b6a9c13db3e3f47c520517d58990a462a1397a61db" dependencies = [ "cc", "openssl-sys", @@ -3446,7 +3471,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown", + "hashbrown 0.15.4", ] [[package]] @@ -5202,11 +5227,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rsqlite-vfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1", + "thiserror 2.0.18", +] + [[package]] name = "rusqlite" -version = "0.37.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +checksum = "11438310b19e3109b6446c33d1ed5e889428cf2e278407bc7896bc4aaea43323" dependencies = [ "bitflags 2.11.0", "fallible-iterator", @@ -5214,6 +5249,7 @@ dependencies = [ "hashlink", "libsqlite3-sys", "smallvec", + "sqlite-wasm-rs", ] [[package]] @@ -5918,6 +5954,18 @@ dependencies = [ "der", ] +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -6813,48 +6861,32 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6862,22 +6894,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.118", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -6897,9 +6929,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 20ff5f2f59..16a27ebd78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -194,7 +194,7 @@ nu-ansi-term = "0.50" num-traits = "0.2" rand = "0.9" regex = "1.12" -rusqlite = "0.37" +rusqlite = "0.40" sanitize-filename = "0.6" serde = "1.0" serde_json = "1" diff --git a/deny.toml b/deny.toml index 45e7bae71b..71a619a120 100644 --- a/deny.toml +++ b/deny.toml @@ -69,7 +69,10 @@ skip = [ { name = "derive_more-impl", version = "1.0.0" }, { name = "derive_more", version = "1.0.0" }, { name = "event-listener", version = "2.5.3" }, + { name = "foldhash", version = "0.1.5" }, { name = "getrandom", version = "0.2.12" }, + { name = "hashbrown", version = "0.15.4" }, + { name = "hashbrown", version = "0.16.1" }, { name = "heck", version = "0.4.1" }, { name = "http", version = "0.2.12" }, { name = "hybrid-array", version = "0.2.3" }, diff --git a/src/constants.rs b/src/constants.rs index 9b109c0f59..d12535cd1f 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -234,7 +234,7 @@ Here is what to do: If you have any questions, please send an email to delta@merlinux.eu or ask at https://support.delta.chat/."#; /// How many recent messages should be re-sent to a new broadcast member. -pub(crate) const N_MSGS_TO_NEW_BROADCAST_MEMBER: usize = 10; +pub(crate) const N_MSGS_TO_NEW_BROADCAST_MEMBER: u32 = 10; #[cfg(test)] mod tests { diff --git a/src/net.rs b/src/net.rs index 01cf1c03c6..95b05f5e8d 100644 --- a/src/net.rs +++ b/src/net.rs @@ -33,7 +33,7 @@ use tls::wrap_tls; pub(crate) const TIMEOUT: Duration = Duration::from_secs(60); /// TTL for caches in seconds. -pub(crate) const CACHE_TTL: u64 = 30 * 24 * 60 * 60; +pub(crate) const CACHE_TTL: u32 = 30 * 24 * 60 * 60; /// Removes connection history entries after `CACHE_TTL`. pub(crate) async fn prune_connection_history(context: &Context) -> Result<()> { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index c91cdea22b..c00e484030 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -2737,6 +2737,12 @@ async fn lookup_or_create_adhoc_group( for &id in &contact_ids { stmt.execute((id,)).context("INSERT INTO temp.contacts")?; } + + // Contact IDs are 32-bit internally, + // so this conversion of contact ID set size + // to u32 should never fail. + let contact_ids_len = u32::try_from(contact_ids.len())?; + let val = t .query_row( "SELECT c.id, c.blocked @@ -2750,7 +2756,7 @@ async fn lookup_or_create_adhoc_group( AND contact_id NOT IN (SELECT id FROM temp.contacts) AND add_timestamp >= remove_timestamp)=0 ORDER BY m.timestamp DESC", - (&grpname, contact_ids.len()), + (&grpname, contact_ids_len), |row| { let id: ChatId = row.get(0)?; let blocked: Blocked = row.get(1)?; diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 095c11fece..3326820dac 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -658,7 +658,7 @@ pub(crate) async fn msgs_to_key_contacts(context: &Context) -> Result<()> { return Ok(()); } let trans_fn = |t: &mut rusqlite::Transaction| { - let mut first_key_contacts_msg_id: u64 = t + let mut first_key_contacts_msg_id: u32 = t .query_one( "SELECT CAST(value AS INTEGER) FROM config WHERE keyname='first_key_contacts_msg_id'", (), @@ -682,10 +682,10 @@ pub(crate) async fn msgs_to_key_contacts(context: &Context) -> Result<()> { ) .context("Prepare stmt")?; let msgs_to_migrate = 1000; - let mut msgs_migrated: u64 = 0; + let mut msgs_migrated: u32 = 0; while first_key_contacts_msg_id > 0 && msgs_migrated < msgs_to_migrate { let start_msg_id = first_key_contacts_msg_id.saturating_sub(msgs_to_migrate); - let cnt: u64 = stmt + let cnt: u32 = stmt .execute((start_msg_id, first_key_contacts_msg_id)) .context("UPDATE msgs")? .try_into()?; diff --git a/src/stats.rs b/src/stats.rs index 264f449df1..c7aa60bc70 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -77,7 +77,7 @@ struct ContactStat { #[serde(skip_serializing_if = "is_false")] direct_chat: bool, - last_seen: u64, + last_seen: i64, #[serde(skip_serializing_if = "Option::is_none")] transitive_chain: Option, @@ -328,7 +328,7 @@ async fn ensure_last_old_contact_id(context: &Context) -> Result<()> { return Ok(()); } - let last_contact_id: u64 = context + let last_contact_id: u32 = context .sql .query_get_value("SELECT MAX(id) FROM contacts", ()) .await? @@ -451,7 +451,7 @@ async fn get_contact_stats(context: &Context, last_old_contact: u32) -> Result Result { let blobdir_size = tokio::task::spawn_blocking(move || get_blobdir_storage_usage(&context_clone)); - let page_size: u64 = ctx + let page_size: i64 = ctx .sql .query_get_value("PRAGMA page_size", ()) .await? .unwrap_or_default(); - let page_count: u64 = ctx + let page_size = u64::try_from(page_size)?; + let page_count: i64 = ctx .sql .query_get_value("PRAGMA page_count", ()) .await? .unwrap_or_default(); + let page_count = u64::try_from(page_count)?; let mut largest_tables = ctx .sql @@ -78,7 +80,8 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { (), |row| { let name: String = row.get(0)?; - let size: u64 = row.get(1)?; + let size: i64 = row.get(1)?; + let size: u64 = u64::try_from(size)?; Ok((name, size, None)) }, ) @@ -86,12 +89,13 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { for row in &mut largest_tables { let name = &row.0; - let row_count: Result> = ctx + let row_count: Option = ctx .sql // SECURITY: the table name comes from the db, not from the user .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) - .await; - row.2 = row_count.unwrap_or_default(); + .await + .unwrap_or_default(); + row.2 = row_count.map(|count| u64::try_from(count).unwrap_or_default()); } let largest_webxdc_data = ctx @@ -103,8 +107,12 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { (), |row| { let msg_id: MsgId = row.get(0)?; - let size: u64 = row.get(1)?; - let count: u64 = row.get(2)?; + let size: i64 = row.get(1)?; + let count: i64 = row.get(2)?; + + // This should never fail as the count cannot be negative. + let size: u64 = u64::try_from(size)?; + let count: u64 = u64::try_from(count)?; Ok((msg_id, size, count)) },