From a3b2bfd70579d40a4b2a9a986cd0ad16926f4b4e Mon Sep 17 00:00:00 2001 From: Lucas Date: Sat, 18 Nov 2023 02:55:05 +0800 Subject: [PATCH] Minor cleanup (#1008) - Add separators to long literal. - Use first() instead of get(0) - Move some SQL-making code to their own functions - Minor mathematics and rounding cleanup --------- Co-authored-by: Yuri Astrakhan --- Cargo.lock | 5 +- Cargo.toml | 4 +- martin-tile-utils/src/lib.rs | 4 + martin/src/lib.rs | 1 + mbtiles/Cargo.toml | 16 +--- mbtiles/src/copier.rs | 143 +++++++++++++++++++++-------------- mbtiles/src/metadata.rs | 1 + mbtiles/src/patcher.rs | 108 +++++++++++++------------- mbtiles/src/summary.rs | 105 +++++++++++++------------ mbtiles/src/validation.rs | 4 +- mbtiles/tests/mbtiles.rs | 10 +-- 11 files changed, 221 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37fbc9ca2..9e9b3c25f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3633,13 +3633,14 @@ dependencies = [ [[package]] name = "tilejson" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a16212e5ea60f2b406835981338a1df9b206fab312e3470502d60f69e590a9c9" +checksum = "860f93502e95360a4f3989076db613dd8c428798c90b3d8bf07b51cd8916ac0d" dependencies = [ "serde", "serde_json", "serde_tuple", + "thiserror", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ba8382a1..ecbccf3b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,9 @@ readme = "README.md" homepage = "https://martin.maplibre.org/" [workspace.lints.rust] -unsafe_code = "forbid" +# Lints inheritance from workspace is not yet supported +# Crate mbtiles uses unsafe code, so we can't forbid it here +# unsafe_code = "forbid" [workspace.lints.clippy] pedantic = "warn" diff --git a/martin-tile-utils/src/lib.rs b/martin-tile-utils/src/lib.rs index 9caa1f849..da18e284a 100644 --- a/martin-tile-utils/src/lib.rs +++ b/martin-tile-utils/src/lib.rs @@ -3,8 +3,12 @@ // This code was partially adapted from https://github.com/maplibre/mbtileserver-rs // project originally written by Kaveh Karimi and licensed under MIT/Apache-2.0 +use std::f64::consts::PI; use std::fmt::Display; +pub const EARTH_CIRCUMFERENCE: f64 = 40_075_016.7; +pub const EARTH_RADIUS: f64 = EARTH_CIRCUMFERENCE / 2.0 / PI; + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Format { Gif, diff --git a/martin/src/lib.rs b/martin/src/lib.rs index 742ccbac0..a07176bab 100644 --- a/martin/src/lib.rs +++ b/martin/src/lib.rs @@ -1,4 +1,5 @@ #![doc = include_str!("../README.md")] +#![forbid(unsafe_code)] pub mod args; mod config; diff --git a/mbtiles/Cargo.toml b/mbtiles/Cargo.toml index 869665ce7..5c7707dd6 100644 --- a/mbtiles/Cargo.toml +++ b/mbtiles/Cargo.toml @@ -1,3 +1,5 @@ +lints.workspace = true + [package] name = "mbtiles" version = "0.7.4" @@ -52,17 +54,3 @@ path = "src/lib.rs" name = "mbtiles" path = "src/bin/mbtiles.rs" required-features = ["cli"] - -# Lints inheritance from workspace is not yet supported -# Copy/pasting the list, modifying the `unsafe_code` requirement -[lints.rust] -unsafe_code = "allow" - -[lints.clippy] -# We are not ready to use pedantic clippy yet -#pedantic = "warn" -derive_partial_eq_without_eq = "allow" -implicit_hasher = "allow" -missing_errors_doc = "allow" -missing_panics_doc = "allow" -module_name_repetitions = "allow" diff --git a/mbtiles/src/copier.rs b/mbtiles/src/copier.rs index 748174862..ad33a3ca7 100644 --- a/mbtiles/src/copier.rs +++ b/mbtiles/src/copier.rs @@ -6,7 +6,7 @@ use clap::{Args, ValueEnum}; use enum_display::EnumDisplay; use log::{debug, info}; use sqlite_hashes::rusqlite; -use sqlite_hashes::rusqlite::params_from_iter; +use sqlite_hashes::rusqlite::{params_from_iter, Connection}; use sqlx::{query, Executor as _, Row, SqliteConnection}; use crate::errors::MbtResult; @@ -195,57 +195,45 @@ impl MbtileCopierInt { let (on_dupl, sql_cond) = self.get_on_duplicate_sql(dst_type); debug!("Copying tiles with 'INSERT {on_dupl}' {src_type} -> {dst_type} ({sql_cond})"); - // Make sure not to execute any other queries while the handle is locked - let mut handle_lock = conn.lock_handle().await?; - let handle = handle_lock.as_raw_handle().as_ptr(); - // SAFETY: this is safe as long as handle_lock is valid. We will drop the lock. - let rusqlite_conn = unsafe { rusqlite::Connection::from_handle(handle) }?; + { + // SAFETY: This must be scoped to make sure the handle is dropped before we continue using conn + // Make sure not to execute any other queries while the handle is locked + let mut handle_lock = conn.lock_handle().await?; + let handle = handle_lock.as_raw_handle().as_ptr(); + + // SAFETY: this is safe as long as handle_lock is valid. We will drop the lock. + let rusqlite_conn = unsafe { rusqlite::Connection::from_handle(handle) }?; + + Self::copy_tiles( + &rusqlite_conn, + dst_type, + &query_args, + &on_dupl, + &select_from, + &sql_cond, + )?; + + self.copy_metadata(&rusqlite_conn, &dif, &on_dupl)?; + } - match dst_type { - Flat => { - let sql = format!( - " - INSERT {on_dupl} INTO tiles - (zoom_level, tile_column, tile_row, tile_data) - {select_from} {sql_cond}" - ); - debug!("Copying to {dst_type} with {sql} {query_args:?}"); - rusqlite_conn.execute(&sql, params_from_iter(query_args))? - } - FlatWithHash => { - let sql = format!( - " - INSERT {on_dupl} INTO tiles_with_hash - (zoom_level, tile_column, tile_row, tile_data, tile_hash) - {select_from} {sql_cond}" - ); - debug!("Copying to {dst_type} with {sql} {query_args:?}"); - rusqlite_conn.execute(&sql, params_from_iter(query_args))? - } - Normalized { .. } => { - let sql = format!( - " - INSERT OR IGNORE INTO images - (tile_id, tile_data) - SELECT tile_hash as tile_id, tile_data - FROM ({select_from})" - ); - debug!("Copying to {dst_type} with {sql} {query_args:?}"); - rusqlite_conn.execute(&sql, params_from_iter(&query_args))?; + if !self.options.skip_agg_tiles_hash { + dst_mbt.update_agg_tiles_hash(&mut conn).await?; + } - let sql = format!( - " - INSERT {on_dupl} INTO map - (zoom_level, tile_column, tile_row, tile_id) - SELECT zoom_level, tile_column, tile_row, tile_hash as tile_id - FROM ({select_from} {sql_cond})" - ); - debug!("Copying to {dst_type} with {sql} {query_args:?}"); - rusqlite_conn.execute(&sql, params_from_iter(query_args))? - } - }; + detach_db(&mut conn, "sourceDb").await?; + // Ignore error because we might not have attached diffDb + let _ = detach_db(&mut conn, "diffDb").await; + + Ok(conn) + } + fn copy_metadata( + &self, + rusqlite_conn: &Connection, + dif: &Option<(Mbtiles, MbtType, MbtType)>, + on_dupl: &str, + ) -> Result<(), MbtError> { let sql; if dif.is_some() { // Insert all rows from diffDb.metadata if they do not exist or are different in sourceDb.metadata. @@ -295,20 +283,59 @@ impl MbtileCopierInt { debug!("Copying metadata with {sql}"); } rusqlite_conn.execute(&sql, [])?; + Ok(()) + } - // SAFETY: must drop rusqlite_conn before handle_lock, or place the code since lock in a separate scope - drop(rusqlite_conn); - drop(handle_lock); + fn copy_tiles( + rusqlite_conn: &Connection, + dst_type: MbtType, + query_args: &Vec, + on_dupl: &str, + select_from: &str, + sql_cond: &str, + ) -> Result<(), MbtError> { + let sql = match dst_type { + Flat => { + format!( + " + INSERT {on_dupl} INTO tiles + (zoom_level, tile_column, tile_row, tile_data) + {select_from} {sql_cond}" + ) + } + FlatWithHash => { + format!( + " + INSERT {on_dupl} INTO tiles_with_hash + (zoom_level, tile_column, tile_row, tile_data, tile_hash) + {select_from} {sql_cond}" + ) + } + Normalized { .. } => { + let sql = format!( + " + INSERT OR IGNORE INTO images + (tile_id, tile_data) + SELECT tile_hash as tile_id, tile_data + FROM ({select_from})" + ); + debug!("Copying to {dst_type} with {sql} {query_args:?}"); + rusqlite_conn.execute(&sql, params_from_iter(query_args))?; - if !self.options.skip_agg_tiles_hash { - dst_mbt.update_agg_tiles_hash(&mut conn).await?; - } + format!( + " + INSERT {on_dupl} INTO map + (zoom_level, tile_column, tile_row, tile_id) + SELECT zoom_level, tile_column, tile_row, tile_hash as tile_id + FROM ({select_from} {sql_cond})" + ) + } + }; - detach_db(&mut conn, "sourceDb").await?; - // Ignore error because we might not have attached diffDb - let _ = detach_db(&mut conn, "diffDb").await; + debug!("Copying to {dst_type} with {sql} {query_args:?}"); + rusqlite_conn.execute(&sql, params_from_iter(query_args))?; - Ok(conn) + Ok(()) } /// Check if the detected destination file type matches the one given by the options diff --git a/mbtiles/src/metadata.rs b/mbtiles/src/metadata.rs index 725e1e3bb..a48c20add 100644 --- a/mbtiles/src/metadata.rs +++ b/mbtiles/src/metadata.rs @@ -23,6 +23,7 @@ pub struct Metadata { pub json: Option, } +#[allow(clippy::trivially_copy_pass_by_ref)] fn serialize_ti(ti: &TileInfo, serializer: S) -> Result { let mut s = serializer.serialize_struct("TileInfo", 2)?; s.serialize_field("format", &ti.format.to_string())?; diff --git a/mbtiles/src/patcher.rs b/mbtiles/src/patcher.rs index 94444a917..1da5c2ff9 100644 --- a/mbtiles/src/patcher.rs +++ b/mbtiles/src/patcher.rs @@ -5,7 +5,7 @@ use sqlx::query; use crate::queries::detach_db; use crate::MbtType::{Flat, FlatWithHash, Normalized}; -use crate::{MbtResult, Mbtiles, AGG_TILES_HASH, AGG_TILES_HASH_IN_DIFF}; +use crate::{MbtResult, MbtType, Mbtiles, AGG_TILES_HASH, AGG_TILES_HASH_IN_DIFF}; pub async fn apply_patch(src_file: PathBuf, patch_file: PathBuf) -> MbtResult<()> { let src_mbt = Mbtiles::new(src_file)?; @@ -17,7 +17,59 @@ pub async fn apply_patch(src_file: PathBuf, patch_file: PathBuf) -> MbtResult<() patch_mbt.attach_to(&mut conn, "patchDb").await?; info!("Applying patch file {patch_mbt} ({patch_type}) to {src_mbt} ({src_type})"); - let select_from = if src_type == Flat { + let select_from = get_select_from(src_type, patch_type); + let (main_table, insert_sql) = get_insert_sql(src_type, select_from); + + for statement in insert_sql { + query(&format!("{statement} WHERE tile_data NOTNULL")) + .execute(&mut conn) + .await?; + } + + query(&format!( + " + DELETE FROM {main_table} + WHERE (zoom_level, tile_column, tile_row) IN ( + SELECT zoom_level, tile_column, tile_row FROM ({select_from} WHERE tile_data ISNULL) + )" + )) + .execute(&mut conn) + .await?; + + if src_type.is_normalized() { + debug!("Removing unused tiles from the images table (normalized schema)"); + query("DELETE FROM images WHERE tile_id NOT IN (SELECT tile_id FROM map)") + .execute(&mut conn) + .await?; + } + + // Copy metadata from patchDb to the destination file, replacing existing values + // Convert 'agg_tiles_hash_in_patch' into 'agg_tiles_hash' + // Delete metadata entries if the value is NULL in patchDb + query(&format!( + " + INSERT OR REPLACE INTO metadata (name, value) + SELECT IIF(name = '{AGG_TILES_HASH_IN_DIFF}', '{AGG_TILES_HASH}', name) as name, + value + FROM patchDb.metadata + WHERE name NOTNULL AND name != '{AGG_TILES_HASH}';" + )) + .execute(&mut conn) + .await?; + + query( + " + DELETE FROM metadata + WHERE name IN (SELECT name FROM patchDb.metadata WHERE value ISNULL);", + ) + .execute(&mut conn) + .await?; + + detach_db(&mut conn, "patchDb").await +} + +fn get_select_from(src_type: MbtType, patch_type: MbtType) -> &'static str { + if src_type == Flat { "SELECT zoom_level, tile_column, tile_row, tile_data FROM patchDb.tiles" } else { match patch_type { @@ -39,9 +91,10 @@ pub async fn apply_patch(src_file: PathBuf, patch_file: PathBuf) -> MbtResult<() } } } - .to_string(); +} - let (main_table, insert_sql) = match src_type { +fn get_insert_sql(src_type: MbtType, select_from: &str) -> (&'static str, Vec) { + match src_type { Flat => ( "tiles", vec![format!( @@ -75,54 +128,7 @@ pub async fn apply_patch(src_file: PathBuf, patch_file: PathBuf) -> MbtResult<() ), ], ), - }; - - for statement in insert_sql { - query(&format!("{statement} WHERE tile_data NOTNULL")) - .execute(&mut conn) - .await?; - } - - query(&format!( - " - DELETE FROM {main_table} - WHERE (zoom_level, tile_column, tile_row) IN ( - SELECT zoom_level, tile_column, tile_row FROM ({select_from} WHERE tile_data ISNULL) - )" - )) - .execute(&mut conn) - .await?; - - if src_type.is_normalized() { - debug!("Removing unused tiles from the images table (normalized schema)"); - query("DELETE FROM images WHERE tile_id NOT IN (SELECT tile_id FROM map)") - .execute(&mut conn) - .await?; } - - // Copy metadata from patchDb to the destination file, replacing existing values - // Convert 'agg_tiles_hash_in_patch' into 'agg_tiles_hash' - // Delete metadata entries if the value is NULL in patchDb - query(&format!( - " - INSERT OR REPLACE INTO metadata (name, value) - SELECT IIF(name = '{AGG_TILES_HASH_IN_DIFF}', '{AGG_TILES_HASH}', name) as name, - value - FROM patchDb.metadata - WHERE name NOTNULL AND name != '{AGG_TILES_HASH}';" - )) - .execute(&mut conn) - .await?; - - query( - " - DELETE FROM metadata - WHERE name IN (SELECT name FROM patchDb.metadata WHERE value ISNULL);", - ) - .execute(&mut conn) - .await?; - - detach_db(&mut conn, "patchDb").await } #[cfg(test)] diff --git a/mbtiles/src/summary.rs b/mbtiles/src/summary.rs index 2bfe31850..03131f35b 100644 --- a/mbtiles/src/summary.rs +++ b/mbtiles/src/summary.rs @@ -1,7 +1,14 @@ +#![allow( + clippy::cast_possible_truncation, + clippy::cast_precision_loss, + clippy::cast_sign_loss +)] + use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::str::FromStr; +use martin_tile_utils::{EARTH_CIRCUMFERENCE, EARTH_RADIUS}; use serde::Serialize; use size_format::SizeFormatterBinary; use sqlx::{query, SqliteExecutor}; @@ -102,7 +109,7 @@ impl Display for Summary { } impl Mbtiles { - /// Compute MBTiles file summary + /// Compute `MBTiles` file summary pub async fn summary(&self, conn: &mut T) -> MbtResult where for<'e> &'e mut T: SqliteExecutor<'e>, @@ -182,23 +189,23 @@ impl Mbtiles { /// Convert min/max XYZ tile coordinates to a bounding box fn xyz_to_bbox(zoom: u8, min_x: i32, min_y: i32, max_x: i32, max_y: i32) -> Bounds { - let tile_size = 40075016.7 / (2_u32.pow(zoom as u32)) as f64; + let tile_size = EARTH_CIRCUMFERENCE / f64::from(1 << zoom); let (min_lng, min_lat) = webmercator_to_wgs84( - -20037508.34 + min_x as f64 * tile_size, - -20037508.34 + min_y as f64 * tile_size, + -0.5 * EARTH_CIRCUMFERENCE + f64::from(min_x) * tile_size, + -0.5 * EARTH_CIRCUMFERENCE + f64::from(min_y) * tile_size, ); let (max_lng, max_lat) = webmercator_to_wgs84( - -20037508.34 + (max_x as f64 + 1.0) * tile_size, - -20037508.34 + (max_y as f64 + 1.0) * tile_size, + -0.5 * EARTH_CIRCUMFERENCE + f64::from(max_x + 1) * tile_size, + -0.5 * EARTH_CIRCUMFERENCE + f64::from(max_y + 1) * tile_size, ); Bounds::new(min_lng, min_lat, max_lng, max_lat) } fn get_zoom_precision(zoom: u8) -> usize { - let lng_delta = webmercator_to_wgs84(40075016.7 / (2_u32.pow(zoom as u32)) as f64, 0f64).0; + let lng_delta = webmercator_to_wgs84(EARTH_CIRCUMFERENCE / f64::from(1 << zoom), 0.0).0; let log = lng_delta.log10() - 0.5; - if log > 0_f64 { + if log > 0.0 { 0 } else { -log.ceil() as usize @@ -206,13 +213,15 @@ fn get_zoom_precision(zoom: u8) -> usize { } fn webmercator_to_wgs84(x: f64, y: f64) -> (f64, f64) { - let lng = (x / 6378137.0).to_degrees(); - let lat = (f64::atan(f64::sinh(y / 6378137.0))).to_degrees(); + let lng = (x / EARTH_RADIUS).to_degrees(); + let lat = (f64::atan(f64::sinh(y / EARTH_RADIUS))).to_degrees(); (lng, lat) } #[cfg(test)] mod tests { + #![allow(clippy::unreadable_literal)] + use approx::assert_relative_eq; use insta::assert_yaml_snapshot; @@ -222,20 +231,20 @@ mod tests { #[actix_rt::test] async fn meter_to_lnglat() { let (lng, lat) = webmercator_to_wgs84(-20037508.34, -20037508.34); - assert_relative_eq!(lng, -179.99999997494382, epsilon = f64::EPSILON); - assert_relative_eq!(lat, -85.05112877764508, epsilon = f64::EPSILON); + assert_relative_eq!(lng, -179.99999991016847, epsilon = f64::EPSILON); + assert_relative_eq!(lat, -85.05112877205713, epsilon = f64::EPSILON); let (lng, lat) = webmercator_to_wgs84(20037508.34, 20037508.34); - assert_relative_eq!(lng, 179.99999997494382, epsilon = f64::EPSILON); - assert_relative_eq!(lat, 85.05112877764508, epsilon = f64::EPSILON); + assert_relative_eq!(lng, 179.99999991016847, epsilon = f64::EPSILON); + assert_relative_eq!(lat, 85.05112877205713, epsilon = f64::EPSILON); let (lng, lat) = webmercator_to_wgs84(0.0, 0.0); assert_relative_eq!(lng, 0.0, epsilon = f64::EPSILON); assert_relative_eq!(lat, 0.0, epsilon = f64::EPSILON); let (lng, lat) = webmercator_to_wgs84(3000.0, 9000.0); - assert_relative_eq!(lng, 0.026949458523585643, epsilon = f64::EPSILON); - assert_relative_eq!(lat, 0.08084834874097371, epsilon = f64::EPSILON); + assert_relative_eq!(lng, 0.02694945851388753, epsilon = f64::EPSILON); + assert_relative_eq!(lat, 0.0808483487118794, epsilon = f64::EPSILON); } #[actix_rt::test] @@ -282,10 +291,10 @@ mod tests { max_tile_size: 1107 avg_tile_size: 96.2295918367347 bbox: - - -179.99999997494382 - - -85.05112877764508 - - 180.00000015460688 - - 85.05112879314403 + - -180 + - -85.0511287798066 + - 180 + - 85.0511287798066 min_zoom: 0 max_zoom: 6 zoom_info: @@ -295,70 +304,70 @@ mod tests { max_tile_size: 1107 avg_tile_size: 1107 bbox: - - -179.99999997494382 - - -85.05112877764508 - - 180.00000015460688 - - 85.05112879314403 + - -180 + - -85.0511287798066 + - 180 + - 85.0511287798066 - zoom: 1 tile_count: 4 min_tile_size: 160 max_tile_size: 650 avg_tile_size: 366.5 bbox: - - -179.99999997494382 - - -85.05112877764508 - - 180.00000015460688 - - 85.05112879314403 + - -180 + - -85.0511287798066 + - 180 + - 85.0511287798066 - zoom: 2 tile_count: 7 min_tile_size: 137 max_tile_size: 495 avg_tile_size: 239.57142857142858 bbox: - - -179.99999997494382 - - -66.51326042021836 - - 180.00000015460688 - - 66.51326049182072 + - -180 + - -66.51326044311186 + - 180 + - 66.51326044311186 - zoom: 3 tile_count: 17 min_tile_size: 67 max_tile_size: 246 avg_tile_size: 134 bbox: - - -134.99999995874995 - - -40.9798980140281 - - 180.00000015460688 - - 66.51326049182072 + - -135 + - -40.97989806962013 + - 180 + - 66.51326044311186 - zoom: 4 tile_count: 38 min_tile_size: 64 max_tile_size: 175 avg_tile_size: 86 bbox: - - -134.99999995874995 - - -40.9798980140281 - - 180.00000015460688 - - 66.51326049182072 + - -135 + - -40.97989806962013 + - 180 + - 66.51326044311186 - zoom: 5 tile_count: 57 min_tile_size: 64 max_tile_size: 107 avg_tile_size: 72.7719298245614 bbox: - - -123.74999995470151 - - -40.9798980140281 - - 180.00000015460688 - - 61.60639642757953 + - -123.75000000000001 + - -40.97989806962013 + - 180 + - 61.60639637138627 - zoom: 6 tile_count: 72 min_tile_size: 64 max_tile_size: 97 avg_tile_size: 68.29166666666667 bbox: - - -123.74999995470151 - - -40.9798980140281 - - 180.00000015460688 - - 61.60639642757953 + - -123.75000000000001 + - -40.97989806962013 + - 180 + - 61.60639637138627 "###); Ok(()) diff --git a/mbtiles/src/validation.rs b/mbtiles/src/validation.rs index c1e944cc4..67910c8fc 100644 --- a/mbtiles/src/validation.rs +++ b/mbtiles/src/validation.rs @@ -37,10 +37,12 @@ pub enum MbtType { } impl MbtType { + #[must_use] pub fn is_normalized(&self) -> bool { matches!(self, Self::Normalized { .. }) } + #[must_use] pub fn is_normalized_with_view(&self) -> bool { matches!(self, Self::Normalized { hash_view: true }) } @@ -278,7 +280,7 @@ impl Mbtiles { .await?; if result.len() > 1 - || result.get(0).ok_or(FailedIntegrityCheck( + || result.first().ok_or(FailedIntegrityCheck( self.filepath().to_string(), vec!["SQLite could not perform integrity check".to_string()], ))? != "ok" diff --git a/mbtiles/tests/mbtiles.rs b/mbtiles/tests/mbtiles.rs index 511c5512b..d0551a139 100644 --- a/mbtiles/tests/mbtiles.rs +++ b/mbtiles/tests/mbtiles.rs @@ -108,14 +108,14 @@ macro_rules! open { }}; } -/// Create a new SQLite file of given type without agg_tiles_hash metadata value +/// Create a new `SQLite` file of given type without `agg_tiles_hash` metadata value macro_rules! new_file_no_hash { ($function:ident, $dst_type_cli:expr, $sql_meta:expr, $sql_data:expr, $($arg:tt)*) => {{ new_file!(@true, $function, $dst_type_cli, $sql_meta, $sql_data, $($arg)*) }}; } -/// Create a new SQLite file of type $dst_type_cli with the given metadata and tiles +/// Create a new `SQLite` file of type `$dst_type_cli` with the given metadata and tiles macro_rules! new_file { ($function:ident, $dst_type_cli:expr, $sql_meta:expr, $sql_data:expr, $($arg:tt)*) => { new_file!(@false, $function, $dst_type_cli, $sql_meta, $sql_data, $($arg)*) @@ -276,7 +276,7 @@ async fn diff_and_patch( #[notrace] databases: &Databases, ) -> MbtResult<()> { let (v1, v2) = (shorten(v1_type), shorten(v2_type)); - let dif = dif_type.map(shorten).unwrap_or("dflt"); + let dif = dif_type.map_or("dflt", shorten); let prefix = format!("{v2}-{v1}={dif}"); let v1_mbt = databases.mbtiles("v1", v1_type); @@ -341,7 +341,7 @@ async fn patch_on_copy( #[notrace] databases: &Databases, ) -> MbtResult<()> { let (v1, dif) = (shorten(v1_type), shorten(dif_type)); - let v2 = v2_type.map(shorten).unwrap_or("dflt"); + let v2 = v2_type.map_or("dflt", shorten); let prefix = format!("{v1}+{dif}={v2}"); let v1_mbt = databases.mbtiles("v1", v1_type); @@ -417,7 +417,7 @@ async fn dump(conn: &mut SqliteConnection) -> MbtResult> { .await? .into_iter() .map(|row| { - let cid: i32 = row.get(0); + let cid: u32 = row.get(0); let typ: String = row.get(2); (cid as usize, typ) })