From 2d2167e048b7c5afe1ef35acd9e2b32472268958 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Wed, 22 Oct 2025 17:33:55 +0800 Subject: [PATCH] refactor: replace unwrap_or with unwrap_or_else for improved error handling (#5163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Rust, the `or` and `or_else` methods have distinct behavioral differences. The `or` method always eagerly evaluates its argument and executes any associated function calls. This can lead to unnecessary performance costs—especially in expensive operations like string processing or file handling—and may even trigger unintended side effects. In contrast, `or_else` evaluates its closure lazily, only when necessary. Introducing a Clippy lint to disallow `or` sacrifices a bit of code simplicity but ensures predictable behavior and enforces lazy evaluation for better performance. --- src-tauri/Cargo.toml | 2 ++ src-tauri/src/cmd/runtime.rs | 6 ++--- src-tauri/src/config/clash.rs | 2 +- src-tauri/src/config/config.rs | 2 +- src-tauri/src/config/prfitem.rs | 11 +++++---- src-tauri/src/config/profiles.rs | 7 ++++-- src-tauri/src/config/runtime.rs | 8 +++---- src-tauri/src/core/service.rs | 2 +- src-tauri/src/core/tray/mod.rs | 33 +++++++++++++++++++-------- src-tauri/src/enhance/chain.rs | 2 +- src-tauri/src/enhance/mod.rs | 6 ++--- src-tauri/src/enhance/tun.rs | 8 +++---- src-tauri/src/module/sysinfo.rs | 6 ++--- src-tauri/src/utils/dirs.rs | 4 ++-- src-tauri/src/utils/help.rs | 7 +++--- src-tauri/src/utils/init.rs | 10 ++++---- src-tauri/src/utils/resolve/window.rs | 2 +- src-tauri/src/utils/server.rs | 4 ++-- 18 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b9164116..cedc9f62 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -221,3 +221,5 @@ needless_raw_string_hashes = "deny" # Too many in existing code #pedantic = { level = "allow", priority = -1 } #nursery = { level = "allow", priority = -1 } #restriction = { level = "allow", priority = -1 } + +or_fun_call = "deny" \ No newline at end of file diff --git a/src-tauri/src/cmd/runtime.rs b/src-tauri/src/cmd/runtime.rs index a45f6597..05ae1252 100644 --- a/src-tauri/src/cmd/runtime.rs +++ b/src-tauri/src/cmd/runtime.rs @@ -1,6 +1,6 @@ use super::CmdResult; use crate::{cmd::StringifyErr, config::*, core::CoreManager, log_err}; -use anyhow::Context; +use anyhow::{Context, anyhow}; use serde_yaml_ng::Mapping; use smartstring::alias::String; use std::collections::HashMap; @@ -19,7 +19,7 @@ pub async fn get_runtime_yaml() -> CmdResult { let config = runtime.config.as_ref(); config - .ok_or(anyhow::anyhow!("failed to parse config to yaml file")) + .ok_or_else(|| anyhow!("failed to parse config to yaml file")) .and_then(|config| { serde_yaml_ng::to_string(config) .context("failed to convert config to yaml") @@ -48,7 +48,7 @@ pub async fn get_runtime_proxy_chain_config(proxy_chain_exit_node: String) -> Cm let config = runtime .config .as_ref() - .ok_or(anyhow::anyhow!("failed to parse config to yaml file")) + .ok_or_else(|| anyhow!("failed to parse config to yaml file")) .stringify_err()?; if let Some(serde_yaml_ng::Value::Sequence(proxies)) = config.get("proxies") { diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 9450aaee..ac216933 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -287,7 +287,7 @@ impl IClashTemp { } None => None, }) - .unwrap_or("127.0.0.1:9097".into()) + .unwrap_or_else(|| "127.0.0.1:9097".into()) } pub fn guard_external_controller(config: &Mapping) -> String { diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 4f50443d..ced80e1d 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -140,7 +140,7 @@ impl Config { .latest_ref() .config .as_ref() - .ok_or(anyhow!("failed to get runtime config"))? + .ok_or_else(|| anyhow!("failed to get runtime config"))? .clone(); drop(runtime); // 显式释放锁 diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index 6888ee3c..7475cf1f 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -164,8 +164,8 @@ impl PrfItem { PrfItem::from_url(url, name, desc, item.option).await } "local" => { - let name = item.name.unwrap_or("Local File".into()); - let desc = item.desc.unwrap_or("".into()); + let name = item.name.unwrap_or_else(|| "Local File".into()); + let desc = item.desc.unwrap_or_else(|| "".into()); PrfItem::from_local(name, desc, file_data, item.option).await } typ => bail!("invalid profile item type \"{typ}\""), @@ -235,7 +235,7 @@ impl PrfItem { }), home: None, updated: Some(chrono::Local::now().timestamp() as usize), - file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())), + file_data: Some(file_data.unwrap_or_else(|| tmpl::ITEM_LOCAL.into())), }) } @@ -331,7 +331,8 @@ impl PrfItem { } } None => Some( - crate::utils::help::get_last_part_and_decode(url).unwrap_or("Remote File".into()), + crate::utils::help::get_last_part_and_decode(url) + .unwrap_or_else(|| "Remote File".into()), ), }; let update_interval = match update_interval { @@ -355,7 +356,7 @@ impl PrfItem { let uid = help::get_uid("R").into(); let file = format!("{uid}.yaml").into(); - let name = name.unwrap_or(filename.unwrap_or("Remote File".into()).into()); + let name = name.unwrap_or_else(|| filename.unwrap_or_else(|| "Remote File".into()).into()); let data = resp.text_with_charset()?; // process the charset "UTF-8 with BOM" diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index 2fef30be..776ee21a 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -241,8 +241,11 @@ impl IProfiles { // move the field value after save if let Some(file_data) = item.file_data.take() { let file = each.file.take(); - let file = file - .unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid).into())); + let file = file.unwrap_or_else(|| { + item.file + .take() + .unwrap_or_else(|| format!("{}.yaml", &uid).into()) + }); // the file must exists each.file = Some(file.clone()); diff --git a/src-tauri/src/config/runtime.rs b/src-tauri/src/config/runtime.rs index db8c9614..e394d5d6 100644 --- a/src-tauri/src/config/runtime.rs +++ b/src-tauri/src/config/runtime.rs @@ -32,11 +32,11 @@ impl IRuntime { let patch_tun = patch.get("tun"); if patch_tun.is_some() { let tun = config.get("tun"); - let mut tun: Mapping = tun.map_or(Mapping::new(), |val| { - val.as_mapping().cloned().unwrap_or(Mapping::new()) + let mut tun: Mapping = tun.map_or_else(Mapping::new, |val| { + val.as_mapping().cloned().unwrap_or_else(Mapping::new) }); - let patch_tun = patch_tun.map_or(Mapping::new(), |val| { - val.as_mapping().cloned().unwrap_or(Mapping::new()) + let patch_tun = patch_tun.map_or_else(Mapping::new, |val| { + val.as_mapping().cloned().unwrap_or_else(Mapping::new) }); use_keys(&patch_tun).into_iter().for_each(|key| { if let Some(value) = patch_tun.get(key.as_str()) { diff --git a/src-tauri/src/core/service.rs b/src-tauri/src/core/service.rs index 2cd4d51c..839855ea 100644 --- a/src-tauri/src/core/service.rs +++ b/src-tauri/src/core/service.rs @@ -330,7 +330,7 @@ async fn check_service_version() -> Result { return Err(anyhow::anyhow!(err_msg)); } - let version = response.data.unwrap_or("unknown".into()); + let version = response.data.unwrap_or_else(|| "unknown".into()); Ok(version) }; diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index abc6cc39..a195ae39 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -84,7 +84,10 @@ impl TrayState { } #[cfg(target_os = "macos")] { - let tray_icon_colorful = verge.tray_icon.unwrap_or("monochrome".into()); + let tray_icon_colorful = verge + .tray_icon + .clone() + .unwrap_or_else(|| "monochrome".into()); if tray_icon_colorful == "monochrome" { ( false, @@ -118,7 +121,10 @@ impl TrayState { } #[cfg(target_os = "macos")] { - let tray_icon_colorful = verge.tray_icon.clone().unwrap_or("monochrome".into()); + let tray_icon_colorful = verge + .tray_icon + .clone() + .unwrap_or_else(|| "monochrome".into()); if tray_icon_colorful == "monochrome" { ( false, @@ -152,7 +158,10 @@ impl TrayState { } #[cfg(target_os = "macos")] { - let tray_icon_colorful = verge.tray_icon.clone().unwrap_or("monochrome".into()); + let tray_icon_colorful = verge + .tray_icon + .clone() + .unwrap_or_else(|| "monochrome".into()); if tray_icon_colorful == "monochrome" { ( false, @@ -219,7 +228,7 @@ impl Tray { let app_handle = handle::Handle::app_handle(); let tray_event = { Config::verge().await.latest_ref().tray_event.clone() }; - let tray_event = tray_event.unwrap_or("main_window".into()); + let tray_event = tray_event.unwrap_or_else(|| "main_window".into()); let tray = app_handle .tray_by_id("main") .ok_or_else(|| anyhow::anyhow!("Failed to get main tray"))?; @@ -350,7 +359,10 @@ impl Tray { (false, false) => TrayState::get_common_tray_icon().await, }; - let colorful = verge.tray_icon.clone().unwrap_or("monochrome".into()); + let colorful = verge + .tray_icon + .clone() + .unwrap_or_else(|| "monochrome".into()); let is_colorful = colorful == "colorful"; let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)); @@ -448,9 +460,10 @@ impl Tray { let profile_text = t("Profile").await; let v = env!("CARGO_PKG_VERSION"); - let reassembled_version = v.split_once('+').map_or(v.into(), |(main, rest)| { - format!("{main}+{}", rest.split('.').next().unwrap_or("")) - }); + let reassembled_version = v.split_once('+').map_or_else( + || v.into(), + |(main, rest)| format!("{main}+{}", rest.split('.').next().unwrap_or("")), + ); let tooltip = format!( "Clash Verge {}\n{}: {}\n{}: {}\n{}: {}", @@ -505,7 +518,7 @@ impl Tray { #[cfg(any(target_os = "macos", target_os = "windows"))] let show_menu_on_left_click = { let tray_event = { Config::verge().await.latest_ref().tray_event.clone() }; - let tray_event: String = tray_event.unwrap_or("main_window".into()); + let tray_event: String = tray_event.unwrap_or_else(|| "main_window".into()); tray_event.as_str() == "tray_menu" }; @@ -526,7 +539,7 @@ impl Tray { tray.on_tray_icon_event(|_app_handle, event| { AsyncHandler::spawn(|| async move { let tray_event = { Config::verge().await.latest_ref().tray_event.clone() }; - let tray_event: String = tray_event.unwrap_or("main_window".into()); + let tray_event: String = tray_event.unwrap_or_else(|| "main_window".into()); log::debug!(target: "app", "tray event: {tray_event:?}"); if let TrayIconEvent::Click { diff --git a/src-tauri/src/enhance/chain.rs b/src-tauri/src/enhance/chain.rs index fa9341f5..8238061c 100644 --- a/src-tauri/src/enhance/chain.rs +++ b/src-tauri/src/enhance/chain.rs @@ -73,7 +73,7 @@ impl AsyncChainItemFrom for Option { async fn from_async(item: &PrfItem) -> Option { let itype = item.itype.as_ref()?.as_str(); let file = item.file.clone()?; - let uid = item.uid.clone().unwrap_or("".into()); + let uid = item.uid.clone().unwrap_or_else(|| "".into()); let path = dirs::app_profiles_dir().ok()?.join(file.as_str()); if !path.exists() { diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index f6ee459e..704f199f 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -296,10 +296,10 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { // 合并默认的config for (key, value) in clash_config.into_iter() { if key.as_str() == Some("tun") { - let mut tun = config.get_mut("tun").map_or(Mapping::new(), |val| { - val.as_mapping().cloned().unwrap_or(Mapping::new()) + let mut tun = config.get_mut("tun").map_or_else(Mapping::new, |val| { + val.as_mapping().cloned().unwrap_or_else(Mapping::new) }); - let patch_tun = value.as_mapping().cloned().unwrap_or(Mapping::new()); + let patch_tun = value.as_mapping().cloned().unwrap_or_else(Mapping::new); for (key, value) in patch_tun.into_iter() { tun.insert(key, value); } diff --git a/src-tauri/src/enhance/tun.rs b/src-tauri/src/enhance/tun.rs index d019960a..92c8f018 100644 --- a/src-tauri/src/enhance/tun.rs +++ b/src-tauri/src/enhance/tun.rs @@ -24,8 +24,8 @@ macro_rules! append { pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping { let tun_key = Value::from("tun"); let tun_val = config.get(&tun_key); - let mut tun_val = tun_val.map_or(Mapping::new(), |val| { - val.as_mapping().cloned().unwrap_or(Mapping::new()) + let mut tun_val = tun_val.map_or_else(Mapping::new, |val| { + val.as_mapping().cloned().unwrap_or_else(Mapping::new) }); if enable { @@ -52,8 +52,8 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping { // 读取DNS配置 let dns_key = Value::from("dns"); let dns_val = config.get(&dns_key); - let mut dns_val = dns_val.map_or(Mapping::new(), |val| { - val.as_mapping().cloned().unwrap_or(Mapping::new()) + let mut dns_val = dns_val.map_or_else(Mapping::new, |val| { + val.as_mapping().cloned().unwrap_or_else(Mapping::new) }); let ipv6_key = Value::from("ipv6"); let ipv6_val = config diff --git a/src-tauri/src/module/sysinfo.rs b/src-tauri/src/module/sysinfo.rs index fb2b2579..74ebe1f3 100644 --- a/src-tauri/src/module/sysinfo.rs +++ b/src-tauri/src/module/sysinfo.rs @@ -33,9 +33,9 @@ impl Debug for PlatformSpecification { impl PlatformSpecification { pub fn new() -> Self { - let system_name = System::name().unwrap_or("Null".into()); - let system_version = System::long_os_version().unwrap_or("Null".into()); - let system_kernel_version = System::kernel_version().unwrap_or("Null".into()); + let system_name = System::name().unwrap_or_else(|| "Null".into()); + let system_version = System::long_os_version().unwrap_or_else(|| "Null".into()); + let system_kernel_version = System::kernel_version().unwrap_or_else(|| "Null".into()); let system_arch = System::cpu_arch(); let handler = handle::Handle::app_handle(); diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index f985fe56..dfbec7ce 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -47,7 +47,7 @@ pub fn app_home_dir() -> Result { let app_exe = dunce::canonicalize(app_exe)?; let app_dir = app_exe .parent() - .ok_or(anyhow::anyhow!("failed to get the portable app dir"))?; + .ok_or_else(|| anyhow::anyhow!("failed to get the portable app dir"))?; return Ok(PathBuf::from(app_dir).join(".config").join(APP_ID)); } @@ -170,7 +170,7 @@ pub fn path_to_str(path: &PathBuf) -> Result<&str> { let path_str = path .as_os_str() .to_str() - .ok_or(anyhow::anyhow!("failed to get path from {:?}", path))?; + .ok_or_else(|| anyhow::anyhow!("failed to get path from {:?}", path))?; Ok(path_str) } diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs index e06c7ed7..8b40f364 100644 --- a/src-tauri/src/utils/help.rs +++ b/src-tauri/src/utils/help.rs @@ -34,10 +34,9 @@ pub async fn read_mapping(path: &PathBuf) -> Result { Ok(val .as_mapping() - .ok_or(anyhow!( - "failed to transform to yaml mapping \"{}\"", - path.display() - ))? + .ok_or_else(|| { + anyhow!("failed to transform to yaml mapping \"{}\"", path.display()) + })? .to_owned()) } Err(err) => { diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index d3e3a277..1488181c 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -155,9 +155,9 @@ pub async fn delete_log() -> Result<()> { let month = u32::from_str(sa[1])?; let day = u32::from_str(sa[2])?; let time = chrono::NaiveDate::from_ymd_opt(year, month, day) - .ok_or(anyhow::anyhow!("invalid time str"))? + .ok_or_else(|| anyhow::anyhow!("invalid time str"))? .and_hms_opt(0, 0, 0) - .ok_or(anyhow::anyhow!("invalid time str"))?; + .ok_or_else(|| anyhow::anyhow!("invalid time str"))?; Ok(time) }; @@ -171,7 +171,7 @@ pub async fn delete_log() -> Result<()> { let file_time = Local .from_local_datetime(&created_time) .single() - .ok_or(anyhow::anyhow!("invalid local datetime"))?; + .ok_or_else(|| anyhow::anyhow!("invalid local datetime"))?; let duration = now.signed_duration_since(file_time); if duration.num_days() > day { @@ -523,7 +523,7 @@ pub async fn startup_script() -> Result<()> { let script_path = { let verge = Config::verge().await; let verge = verge.latest_ref(); - verge.startup_script.clone().unwrap_or("".into()) + verge.startup_script.clone().unwrap_or_else(|| "".into()) }; if script_path.is_empty() { @@ -547,7 +547,7 @@ pub async fn startup_script() -> Result<()> { } let parent_dir = script_dir.parent(); - let working_dir = parent_dir.unwrap_or(script_dir.as_ref()); + let working_dir = parent_dir.unwrap_or_else(|| script_dir.as_ref()); app_handle .shell() diff --git a/src-tauri/src/utils/resolve/window.rs b/src-tauri/src/utils/resolve/window.rs index 46381248..f415f506 100644 --- a/src-tauri/src/utils/resolve/window.rs +++ b/src-tauri/src/utils/resolve/window.rs @@ -26,7 +26,7 @@ pub async fn build_new_window() -> Result { .latest_ref() .start_page .clone() - .unwrap_or("/".into()); + .unwrap_or_else(|| "/".into()); match tauri::WebviewWindowBuilder::new( app_handle, "main", /* the unique window label */ diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 48e5158c..991e29de 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -88,12 +88,12 @@ pub fn embed_server() { .latest_ref() .pac_file_content .clone() - .unwrap_or(DEFAULT_PAC.into()); + .unwrap_or_else(|| DEFAULT_PAC.into()); let pac_port = verge_config .latest_ref() .verge_mixed_port - .unwrap_or(clash_config.latest_ref().get_mixed_port()); + .unwrap_or_else(|| clash_config.latest_ref().get_mixed_port()); let pac = warp::path!("commands" / "pac").map(move || { let processed_content = pac_content.replace("%mixed-port%", &format!("{pac_port}"));