From 040e2a7bb0f2cc5012d46ca99283cf21fa06ed1a Mon Sep 17 00:00:00 2001 From: Mathijs van Veluw Date: Mon, 23 Sep 2024 20:25:32 +0200 Subject: [PATCH] Add extra linting (#4977) * Add extra linting Added extra linting for some code styles. Also added the Rust Edition 2024 lints. Closes #4974 Signed-off-by: BlackDex * Adjusted according to comments Signed-off-by: BlackDex --------- Signed-off-by: BlackDex --- Cargo.lock | 20 +++++++------- Cargo.toml | 28 ++++++++++++++++---- src/api/admin.rs | 6 ++--- src/api/core/accounts.rs | 6 ++--- src/api/core/organizations.rs | 2 +- src/api/core/public.rs | 4 +-- src/api/core/two_factor/email.rs | 2 +- src/api/core/two_factor/protected_actions.rs | 2 +- src/api/core/two_factor/yubikey.rs | 2 +- src/api/icons.rs | 20 +++++++------- src/api/notifications.rs | 2 +- src/auth.rs | 6 ++--- src/config.rs | 10 +++---- src/db/mod.rs | 6 ++--- src/db/models/emergency_access.rs | 2 +- src/db/models/organization.rs | 6 ++--- src/db/models/user.rs | 4 +-- src/error.rs | 2 +- src/http_client.rs | 6 ++--- src/main.rs | 8 +++--- src/util.rs | 8 +++--- 21 files changed, 82 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c613936b..10ed3506 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2543,9 +2543,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" @@ -2564,9 +2564,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "powerfmt" @@ -3226,9 +3226,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -3573,18 +3573,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 5e879834..63060089 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -198,33 +198,46 @@ lto = "thin" codegen-units = 16 # Linting config +# https://doc.rust-lang.org/rustc/lints/groups.html [lints.rust] # Forbid unsafe_code = "forbid" non_ascii_idents = "forbid" # Deny +deprecated_in_future = "deny" future_incompatible = { level = "deny", priority = -1 } +keyword_idents = { level = "deny", priority = -1 } +let_underscore = { level = "deny", priority = -1 } noop_method_call = "deny" +refining_impl_trait = { level = "deny", priority = -1 } rust_2018_idioms = { level = "deny", priority = -1 } rust_2021_compatibility = { level = "deny", priority = -1 } +# rust_2024_compatibility = { level = "deny", priority = -1 } # Enable once we are at MSRV 1.81.0 +single_use_lifetimes = "deny" trivial_casts = "deny" trivial_numeric_casts = "deny" unused = { level = "deny", priority = -1 } unused_import_braces = "deny" unused_lifetimes = "deny" -deprecated_in_future = "deny" +unused_qualifications = "deny" +variant_size_differences = "deny" +# The lints below are part of the rust_2024_compatibility group +static-mut-refs = "deny" +unsafe-op-in-unsafe-fn = "deny" +# https://rust-lang.github.io/rust-clippy/stable/index.html [lints.clippy] -# Allow -# We need this since Rust v1.76+, since it has some bugs -# https://github.com/rust-lang/rust-clippy/issues/12016 -blocks_in_conditions = "allow" +# Warn +dbg_macro = "warn" +todo = "warn" # Deny +case_sensitive_file_extension_comparisons = "deny" cast_lossless = "deny" clone_on_ref_ptr = "deny" equatable_if_let = "deny" +filter_map_next = "deny" float_cmp_const = "deny" inefficient_to_string = "deny" iter_on_empty_collections = "deny" @@ -234,13 +247,18 @@ macro_use_imports = "deny" manual_assert = "deny" manual_instant_elapsed = "deny" manual_string_new = "deny" +match_on_vec_items = "deny" match_wildcard_for_single_variants = "deny" mem_forget = "deny" +needless_continue = "deny" needless_lifetimes = "deny" +option_option = "deny" string_add_assign = "deny" string_to_string = "deny" unnecessary_join = "deny" unnecessary_self_imports = "deny" +unnested_or_patterns = "deny" unused_async = "deny" +unused_self = "deny" verbose_file_reads = "deny" zero_sized_map_values = "deny" diff --git a/src/api/admin.rs b/src/api/admin.rs index 961bbdb3..cc902e39 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -197,7 +197,7 @@ fn post_admin_login( let cookie = Cookie::build((COOKIE_NAME, jwt)) .path(admin_path()) - .max_age(rocket::time::Duration::minutes(CONFIG.admin_session_lifetime())) + .max_age(time::Duration::minutes(CONFIG.admin_session_lifetime())) .same_site(SameSite::Strict) .http_only(true) .secure(secure.https); @@ -717,8 +717,8 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn) "db_version": get_sql_server_version(&mut conn).await, "admin_url": format!("{}/diagnostics", admin_url()), "overrides": &CONFIG.get_overrides().join(", "), - "host_arch": std::env::consts::ARCH, - "host_os": std::env::consts::OS, + "host_arch": env::consts::ARCH, + "host_os": env::consts::OS, "server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(), "server_time": Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(), // Run the server date/time check as late as possible to minimize the time difference "ntp_time": get_ntp_time(has_http_access).await, // Run the ntp check as late as possible to minimize the time difference diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index fc33619d..f9822629 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -223,7 +223,7 @@ pub async fn _register(data: Json, mut conn: DbConn) -> JsonResult } if verified_by_invite && is_email_2fa_required(data.organization_user_id, &mut conn).await { - let _ = email::activate_email_2fa(&user, &mut conn).await; + email::activate_email_2fa(&user, &mut conn).await.ok(); } } @@ -232,7 +232,7 @@ pub async fn _register(data: Json, mut conn: DbConn) -> JsonResult // accept any open emergency access invitations if !CONFIG.mail_enabled() && CONFIG.emergency_access_allowed() { for mut emergency_invite in EmergencyAccess::find_all_invited_by_grantee_email(&user.email, &mut conn).await { - let _ = emergency_invite.accept_invite(&user.uuid, &user.email, &mut conn).await; + emergency_invite.accept_invite(&user.uuid, &user.email, &mut conn).await.ok(); } } @@ -1038,7 +1038,7 @@ async fn put_device_token(uuid: &str, data: Json, headers: Headers, m return Ok(()); } else { // Try to unregister already registered device - let _ = unregister_push_device(device.push_uuid).await; + unregister_push_device(device.push_uuid).await.ok(); } // clear the push_uuid device.push_uuid = None; diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 6d9f055a..3784e74e 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -1720,7 +1720,7 @@ async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> Jso return Ok(Json(json!({}))); } - let invite = crate::auth::decode_invite(token)?; + let invite = decode_invite(token)?; let invite_org_id = match invite.org_id { Some(invite_org_id) => invite_org_id, diff --git a/src/api/core/public.rs b/src/api/core/public.rs index 32b64463..737d30dd 100644 --- a/src/api/core/public.rs +++ b/src/api/core/public.rs @@ -1,6 +1,6 @@ use chrono::Utc; use rocket::{ - request::{self, FromRequest, Outcome}, + request::{FromRequest, Outcome}, serde::json::Json, Request, Route, }; @@ -192,7 +192,7 @@ pub struct PublicToken(String); impl<'r> FromRequest<'r> for PublicToken { type Error = &'static str; - async fn from_request(request: &'r Request<'_>) -> request::Outcome { + async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = request.headers(); // Get access_token let access_token: &str = match headers.get_one("Authorization") { diff --git a/src/api/core/two_factor/email.rs b/src/api/core/two_factor/email.rs index aea238e5..293c0671 100644 --- a/src/api/core/two_factor/email.rs +++ b/src/api/core/two_factor/email.rs @@ -292,7 +292,7 @@ impl EmailTokenData { } pub fn from_json(string: &str) -> Result { - let res: Result = serde_json::from_str(string); + let res: Result = serde_json::from_str(string); match res { Ok(x) => Ok(x), Err(_) => err!("Could not decode EmailTokenData from string"), diff --git a/src/api/core/two_factor/protected_actions.rs b/src/api/core/two_factor/protected_actions.rs index 8bfc59c1..1a1d59c8 100644 --- a/src/api/core/two_factor/protected_actions.rs +++ b/src/api/core/two_factor/protected_actions.rs @@ -42,7 +42,7 @@ impl ProtectedActionData { } pub fn from_json(string: &str) -> Result { - let res: Result = serde_json::from_str(string); + let res: Result = serde_json::from_str(string); match res { Ok(x) => Ok(x), Err(_) => err!("Could not decode ProtectedActionData from string"), diff --git a/src/api/core/two_factor/yubikey.rs b/src/api/core/two_factor/yubikey.rs index 2eff3b6f..b2940353 100644 --- a/src/api/core/two_factor/yubikey.rs +++ b/src/api/core/two_factor/yubikey.rs @@ -49,7 +49,7 @@ fn parse_yubikeys(data: &EnableYubikeyData) -> Vec { data_keys.iter().filter_map(|e| e.as_ref().cloned()).collect() } -fn jsonify_yubikeys(yubikeys: Vec) -> serde_json::Value { +fn jsonify_yubikeys(yubikeys: Vec) -> Value { let mut result = Value::Object(serde_json::Map::new()); for (i, key) in yubikeys.into_iter().enumerate() { diff --git a/src/api/icons.rs b/src/api/icons.rs index 83f3e9e9..6afbaa9f 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashMap, net::IpAddr, sync::Arc, time::{Duration, SystemTime}, @@ -446,6 +447,9 @@ async fn get_page_with_referer(url: &str, referer: &str) -> Result u8 { + static PRIORITY_MAP: Lazy> = + Lazy::new(|| [(".png", 10), (".jpg", 20), (".jpeg", 20)].into_iter().collect()); + // Check if there is a dimension set let (width, height) = parse_sizes(sizes); @@ -470,13 +474,9 @@ fn get_icon_priority(href: &str, sizes: &str) -> u8 { 200 } } else { - // Change priority by file extension - if href.ends_with(".png") { - 10 - } else if href.ends_with(".jpg") || href.ends_with(".jpeg") { - 20 - } else { - 30 + match href.rsplit_once('.') { + Some((_, extension)) => PRIORITY_MAP.get(&*extension.to_ascii_lowercase()).copied().unwrap_or(30), + None => 30, } } } @@ -623,7 +623,7 @@ use cookie_store::CookieStore; pub struct Jar(std::sync::RwLock); impl reqwest::cookie::CookieStore for Jar { - fn set_cookies(&self, cookie_headers: &mut dyn Iterator, url: &url::Url) { + fn set_cookies(&self, cookie_headers: &mut dyn Iterator, url: &url::Url) { use cookie::{Cookie as RawCookie, ParseError as RawCookieParseError}; use time::Duration; @@ -642,7 +642,7 @@ impl reqwest::cookie::CookieStore for Jar { cookie_store.store_response_cookies(cookies, url); } - fn cookies(&self, url: &url::Url) -> Option { + fn cookies(&self, url: &url::Url) -> Option { let cookie_store = self.0.read().unwrap(); let s = cookie_store .get_request_values(url) @@ -654,7 +654,7 @@ impl reqwest::cookie::CookieStore for Jar { return None; } - header::HeaderValue::from_maybe_shared(Bytes::from(s)).ok() + HeaderValue::from_maybe_shared(Bytes::from(s)).ok() } } diff --git a/src/api/notifications.rs b/src/api/notifications.rs index e4707399..8c925e37 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -428,7 +428,7 @@ impl WebSocketUsers { let (user_uuid, collection_uuids, revision_date) = if let Some(collection_uuids) = collection_uuids { ( Value::Nil, - Value::Array(collection_uuids.into_iter().map(|v| v.into()).collect::>()), + Value::Array(collection_uuids.into_iter().map(|v| v.into()).collect::>()), serialize_date(Utc::now().naive_utc()), ) } else { diff --git a/src/auth.rs b/src/auth.rs index 0f4a3076..b1a743da 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -35,8 +35,8 @@ static JWT_FILE_DOWNLOAD_ISSUER: Lazy = Lazy::new(|| format!("{}|file_do static PRIVATE_RSA_KEY: OnceCell = OnceCell::new(); static PUBLIC_RSA_KEY: OnceCell = OnceCell::new(); -pub fn initialize_keys() -> Result<(), crate::error::Error> { - fn read_key(create_if_missing: bool) -> Result<(Rsa, Vec), crate::error::Error> { +pub fn initialize_keys() -> Result<(), Error> { + fn read_key(create_if_missing: bool) -> Result<(Rsa, Vec), Error> { let mut priv_key_buffer = Vec::with_capacity(2048); let mut priv_key_file = File::options() @@ -53,7 +53,7 @@ pub fn initialize_keys() -> Result<(), crate::error::Error> { Rsa::private_key_from_pem(&priv_key_buffer[..bytes_read])? } else if create_if_missing { // Only create the key if the file doesn't exist or is empty - let rsa_key = openssl::rsa::Rsa::generate(2048)?; + let rsa_key = Rsa::generate(2048)?; priv_key_buffer = rsa_key.private_key_to_pem()?; priv_key_file.write_all(&priv_key_buffer)?; info!("Private key '{}' created correctly", CONFIG.private_rsa_key()); diff --git a/src/config.rs b/src/config.rs index d7fb7d3e..eb765b09 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1225,7 +1225,7 @@ impl Config { } pub fn private_rsa_key(&self) -> String { - format!("{}.pem", CONFIG.rsa_key_filename()) + format!("{}.pem", self.rsa_key_filename()) } pub fn mail_enabled(&self) -> bool { let inner = &self.inner.read().unwrap().config; @@ -1256,12 +1256,8 @@ impl Config { token.is_some() && !token.unwrap().trim().is_empty() } - pub fn render_template( - &self, - name: &str, - data: &T, - ) -> Result { - if CONFIG.reload_templates() { + pub fn render_template(&self, name: &str, data: &T) -> Result { + if self.reload_templates() { warn!("RELOADING TEMPLATES"); let hb = load_templates(CONFIG.templates_folder()); hb.render(name, data).map_err(Into::into) diff --git a/src/db/mod.rs b/src/db/mod.rs index 51ffba9c..fe1ab79b 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -300,19 +300,17 @@ pub trait FromDb { impl FromDb for Vec { type Output = Vec; - #[allow(clippy::wrong_self_convention)] #[inline(always)] fn from_db(self) -> Self::Output { - self.into_iter().map(crate::db::FromDb::from_db).collect() + self.into_iter().map(FromDb::from_db).collect() } } impl FromDb for Option { type Output = Option; - #[allow(clippy::wrong_self_convention)] #[inline(always)] fn from_db(self) -> Self::Output { - self.map(crate::db::FromDb::from_db) + self.map(FromDb::from_db) } } diff --git a/src/db/models/emergency_access.rs b/src/db/models/emergency_access.rs index ecfe86fe..e1b85ec6 100644 --- a/src/db/models/emergency_access.rs +++ b/src/db/models/emergency_access.rs @@ -89,7 +89,7 @@ impl EmergencyAccess { Some(user) => user, None => { // remove outstanding invitations which should not exist - let _ = Self::delete_all_by_grantee_email(email, conn).await; + Self::delete_all_by_grantee_email(email, conn).await.ok(); return None; } } diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index cb787017..d39962cc 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -116,7 +116,7 @@ impl PartialOrd for UserOrgType { } fn ge(&self, other: &i32) -> bool { - matches!(self.partial_cmp(other), Some(Ordering::Greater) | Some(Ordering::Equal)) + matches!(self.partial_cmp(other), Some(Ordering::Greater | Ordering::Equal)) } } @@ -139,7 +139,7 @@ impl PartialOrd for i32 { } fn le(&self, other: &UserOrgType) -> bool { - matches!(self.partial_cmp(other), Some(Ordering::Less) | Some(Ordering::Equal) | None) + matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal) | None) } } @@ -632,7 +632,7 @@ impl UserOrganization { } pub async fn find_by_email_and_org(email: &str, org_id: &str, conn: &mut DbConn) -> Option { - if let Some(user) = super::User::find_by_mail(email, conn).await { + if let Some(user) = User::find_by_mail(email, conn).await { if let Some(user_org) = UserOrganization::find_by_user_and_org(&user.uuid, org_id, conn).await { return Some(user_org); } diff --git a/src/db/models/user.rs b/src/db/models/user.rs index a02b694d..d91c91c1 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -144,14 +144,14 @@ impl User { pub fn check_valid_recovery_code(&self, recovery_code: &str) -> bool { if let Some(ref totp_recover) = self.totp_recover { - crate::crypto::ct_eq(recovery_code, totp_recover.to_lowercase()) + crypto::ct_eq(recovery_code, totp_recover.to_lowercase()) } else { false } } pub fn check_valid_api_key(&self, key: &str) -> bool { - matches!(self.api_key, Some(ref api_key) if crate::crypto::ct_eq(api_key, key)) + matches!(self.api_key, Some(ref api_key) if crypto::ct_eq(api_key, key)) } /// Set the password hash generated diff --git a/src/error.rs b/src/error.rs index b2872775..1061a08d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -209,7 +209,7 @@ use rocket::http::{ContentType, Status}; use rocket::request::Request; use rocket::response::{self, Responder, Response}; -impl<'r> Responder<'r, 'static> for Error { +impl Responder<'_, 'static> for Error { fn respond_to(self, _: &Request<'_>) -> response::Result<'static> { match self.error { ErrorKind::Empty(_) => {} // Don't print the error in this situation diff --git a/src/http_client.rs b/src/http_client.rs index b4b8012e..9feba366 100644 --- a/src/http_client.rs +++ b/src/http_client.rs @@ -102,9 +102,9 @@ fn should_block_address_regex(domain_or_ip: &str) -> bool { fn should_block_host(host: Host<&str>) -> Result<(), CustomHttpClientError> { let (ip, host_str): (Option, String) = match host { - url::Host::Ipv4(ip) => (Some(ip.into()), ip.to_string()), - url::Host::Ipv6(ip) => (Some(ip.into()), ip.to_string()), - url::Host::Domain(d) => (None, d.to_string()), + Host::Ipv4(ip) => (Some(ip.into()), ip.to_string()), + Host::Ipv6(ip) => (Some(ip.into()), ip.to_string()), + Host::Domain(d) => (None, d.to_string()), }; if let Some(ip) = ip { diff --git a/src/main.rs b/src/main.rs index 6e725483..e8830f2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,7 +84,7 @@ async fn main() -> Result<(), Error> { let pool = create_db_pool().await; schedule_jobs(pool.clone()); - crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&mut pool.get().await.unwrap()).await.unwrap(); + db::models::TwoFactor::migrate_u2f_to_webauthn(&mut pool.get().await.unwrap()).await.unwrap(); let extra_debug = matches!(level, log::LevelFilter::Trace | log::LevelFilter::Debug); launch_rocket(pool, extra_debug).await // Blocks until program termination. @@ -168,7 +168,7 @@ fn parse_args() { } let argon2 = Argon2::new(Argon2id, V0x13, argon2_params.build().unwrap()); - let salt = SaltString::encode_b64(&crate::crypto::get_random_bytes::<32>()).unwrap(); + let salt = SaltString::encode_b64(&crypto::get_random_bytes::<32>()).unwrap(); let argon2_timer = tokio::time::Instant::now(); if let Ok(password_hash) = argon2.hash_password(password.as_bytes(), &salt) { @@ -204,7 +204,7 @@ fn backup_sqlite() -> Result { use crate::db::{backup_sqlite_database, DbConnType}; if DbConnType::from_url(&CONFIG.database_url()).map(|t| t == DbConnType::sqlite).unwrap_or(false) { use diesel::Connection; - let url = crate::CONFIG.database_url(); + let url = CONFIG.database_url(); // Establish a connection to the sqlite database let mut conn = diesel::sqlite::SqliteConnection::establish(&url)?; @@ -615,7 +615,7 @@ async fn launch_rocket(pool: db::DbPool, extra_debug: bool) -> Result<(), Error> }); } - let _ = instance.launch().await?; + instance.launch().await?; info!("Vaultwarden process exited!"); Ok(()) diff --git a/src/util.rs b/src/util.rs index c586798c..d8433b9a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -213,7 +213,7 @@ impl<'r, R: 'r + Responder<'r, 'static> + Send> Responder<'r, 'static> for Cache }; res.set_raw_header("Cache-Control", cache_control_header); - let time_now = chrono::Local::now(); + let time_now = Local::now(); let expiry_time = time_now + chrono::TimeDelta::try_seconds(self.ttl.try_into().unwrap()).unwrap(); res.set_raw_header("Expires", format_datetime_http(&expiry_time)); Ok(res) @@ -222,8 +222,8 @@ impl<'r, R: 'r + Responder<'r, 'static> + Send> Responder<'r, 'static> for Cache pub struct SafeString(String); -impl std::fmt::Display for SafeString { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for SafeString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -612,7 +612,7 @@ impl<'de> Visitor<'de> for LowerCaseVisitor { fn _process_key(key: &str) -> String { match key.to_lowercase().as_ref() { "ssn" => "ssn".into(), - _ => self::lcase_first(key), + _ => lcase_first(key), } }