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 b91641166..cedc9f625 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 a45f65979..05ae12521 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 9450aaee0..ac2169338 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 4f50443d2..ced80e1d0 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 6888ee3c4..7475cf1f1 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 2fef30be5..776ee21ab 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 db8c96147..e394d5d68 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 2cd4d51ce..839855eac 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 abc6cc392..a195ae392 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 fa9341f56..8238061c8 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 f6ee459e0..704f199f1 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 d019960a2..92c8f0181 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 fb2b25791..74ebe1f3e 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 f985fe569..dfbec7ce2 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 e06c7ed7c..8b40f364b 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 d3e3a277e..1488181ca 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 463812483..f415f5069 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 48e5158c6..991e29de7 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}"));