From 4e9fa51f12aff1ce42c3c12d7d52c32d7e3fc1f3 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sat, 24 Oct 2026 08:17:16 +0000 Subject: [PATCH 1/2] sonar: method paths instead of closures (rust:S1612) Poison recovery, OsStr::to_str and char predicates only; S4325 casts are f64 to f32 and stay. Co-Authored-By: Claude Sonnet 5.5 --- apps/effectcraft-web/src/browse.rs | 2 +- apps/effectcraft-web/src/files.rs | 8 ++--- apps/effectcraft-web/src/store.rs | 2 +- apps/effectcraft/src/main.rs | 2 +- crates/color/src/space.rs | 2 +- crates/effects/src/camera_tracker.rs | 4 +-- crates/effects/src/object_matte.rs | 4 +-- crates/effects/src/ocio.rs | 2 +- crates/effects/src/roto.rs | 16 +++++----- crates/effects/src/util.rs | 4 +-- crates/effects/src/warp_stab.rs | 14 ++++----- crates/engine/src/commands/edit.rs | 2 +- crates/engine/src/commands/file.rs | 2 +- crates/engine/src/commands/layer_menu.rs | 2 +- crates/engine/src/commands/paint.rs | 2 +- crates/engine/src/commands/relink.rs | 2 +- crates/engine/src/mask_track.rs | 4 +-- crates/engine/src/offload.rs | 4 +-- crates/engine/src/render_queue.rs | 2 +- crates/engine/src/tests_proxy.rs | 4 +-- crates/engine/src/tracking.rs | 2 +- crates/engine/src/viewer.rs | 4 +-- crates/export/src/pipeline.rs | 8 ++--- crates/gpu/src/tests_deferred.rs | 2 +- crates/media/src/layered.rs | 2 +- crates/media/src/lib.rs | 2 +- crates/media/src/pool.rs | 4 +-- crates/project/src/lib.rs | 4 +-- crates/render/src/disk_cache.rs | 2 +- crates/render/src/three_d/camera.rs | 2 +- crates/script/src/socket.rs | 8 ++--- crates/text/src/font_dirs.rs | 4 ++- crates/text/src/fonts.rs | 40 ++++++++++++------------ crates/text/src/layout.rs | 8 ++--- crates/text/src/lib.rs | 4 +-- crates/text/src/variable.rs | 8 ++--- crates/ui-egui/src/panels/home.rs | 2 +- xtask/src/main.rs | 4 +-- 38 files changed, 98 insertions(+), 96 deletions(-) diff --git a/apps/effectcraft-web/src/browse.rs b/apps/effectcraft-web/src/browse.rs index ad7500fe..2fd680dc 100644 --- a/apps/effectcraft-web/src/browse.rs +++ b/apps/effectcraft-web/src/browse.rs @@ -52,7 +52,7 @@ struct State { static STATE: LazyLock> = LazyLock::new(Mutex::default); fn state() -> std::sync::MutexGuard<'static, State> { - STATE.lock().unwrap_or_else(|e| e.into_inner()) + STATE.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } /// The web app's Media Browser. diff --git a/apps/effectcraft-web/src/files.rs b/apps/effectcraft-web/src/files.rs index 3f3f3a99..206314e4 100644 --- a/apps/effectcraft-web/src/files.rs +++ b/apps/effectcraft-web/src/files.rs @@ -48,14 +48,14 @@ pub fn list() -> Vec<(String, usize)> { /// The next write of `path` goes to browser storage only (no download). pub fn save_quietly(path: &str) { - QUIET.lock().unwrap_or_else(|e| e.into_inner()).push(path.to_string()); + QUIET.lock().unwrap_or_else(std::sync::PoisonError::into_inner).push(path.to_string()); } /// A rendered file (from the page's exporter or a worker): kept in the table unpersisted and /// downloaded at the next [`flush_downloads`]. pub fn add_output(path: &str, data: Arc<[u8]>) { STORE.put_file(path, data, false); - OUTPUTS.lock().unwrap_or_else(|e| e.into_inner()).push(path.to_string()); + OUTPUTS.lock().unwrap_or_else(std::sync::PoisonError::into_inner).push(path.to_string()); } /// The table path for a picked/dropped file name. @@ -120,7 +120,7 @@ impl Services for WebServices { fn write_file(&self, path: &str, data: &[u8]) -> std::io::Result<()> { put(path, data.into()); let quiet = { - let mut q = QUIET.lock().unwrap_or_else(|e| e.into_inner()); + let mut q = QUIET.lock().unwrap_or_else(std::sync::PoisonError::into_inner); let n = q.len(); q.retain(|p| p != path); q.len() != n @@ -184,7 +184,7 @@ pub fn export_sink() -> Arc { /// Download the render outputs written since the last call. pub fn flush_downloads() { - let paths = std::mem::take(&mut *OUTPUTS.lock().unwrap_or_else(|e| e.into_inner())); + let paths = std::mem::take(&mut *OUTPUTS.lock().unwrap_or_else(std::sync::PoisonError::into_inner)); let mut out: Vec<(String, Arc<[u8]>)> = paths.into_iter().filter_map(|p| get(&p).map(|d| (file_name(&p).to_string(), d))).collect(); out.sort_by(|a, b| a.0.cmp(&b.0)); out.dedup_by(|a, b| a.0 == b.0); diff --git a/apps/effectcraft-web/src/store.rs b/apps/effectcraft-web/src/store.rs index a44a2eac..8aafdac1 100644 --- a/apps/effectcraft-web/src/store.rs +++ b/apps/effectcraft-web/src/store.rs @@ -181,7 +181,7 @@ impl Default for Store { impl Store { pub fn lock(&self) -> std::sync::MutexGuard<'_, Mirror> { - self.mirror.lock().unwrap_or_else(|e| e.into_inner()) + self.mirror.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } fn now(&self) -> f64 { diff --git a/apps/effectcraft/src/main.rs b/apps/effectcraft/src/main.rs index 2bc3265d..c2be93ef 100644 --- a/apps/effectcraft/src/main.rs +++ b/apps/effectcraft/src/main.rs @@ -50,7 +50,7 @@ fn app_icon() -> egui::IconData { fn is_project_file(path: &str) -> bool { std::path::Path::new(path) .extension() - .and_then(|ext| ext.to_str()) + .and_then(std::ffi::OsStr::to_str) .is_some_and(|ext| ext.eq_ignore_ascii_case("ecproj") || ext.eq_ignore_ascii_case("ecprojx")) } diff --git a/crates/color/src/space.rs b/crates/color/src/space.rs index ee7590ec..b570975a 100644 --- a/crates/color/src/space.rs +++ b/crates/color/src/space.rs @@ -177,7 +177,7 @@ impl ColorSpace { /// Parse an id or label (case-insensitive, loose). pub fn parse(s: &str) -> Option { - let k: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let k: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); match k.as_str() { "srgb" | "srgbiec6196621" | "srgbiec61966" | "iec6196621" => Some(ColorSpace::Srgb), "rec709" | "bt709" | "hdtvrec709" | "hdtv" | "709" => Some(ColorSpace::Rec709), diff --git a/crates/effects/src/camera_tracker.rs b/crates/effects/src/camera_tracker.rs index ff4e51fe..ba7878ab 100644 --- a/crates/effects/src/camera_tracker.rs +++ b/crates/effects/src/camera_tracker.rs @@ -136,11 +136,11 @@ type Cache = Mutex>>; fn cached(c: &'static OnceLock>, json: &str, parse: impl Fn(&str) -> Option) -> Option> { let key = fnv(json.as_bytes()); let c = c.get_or_init(Default::default); - if let Some(a) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&key) { + if let Some(a) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key) { return Some(a.clone()); } let a = Arc::new(parse(json)?); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 8 { m.clear(); } diff --git a/crates/effects/src/object_matte.rs b/crates/effects/src/object_matte.rs index d98ec73a..a12d3332 100644 --- a/crates/effects/src/object_matte.rs +++ b/crates/effects/src/object_matte.rs @@ -315,11 +315,11 @@ fn frozen_cache(j: &str) -> Option> { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { return Some(d.clone()); } let d = Arc::new(FrozenCache::from_json(j)?); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 8 { m.clear(); } diff --git a/crates/effects/src/ocio.rs b/crates/effects/src/ocio.rs index 74816b11..e84720a3 100644 --- a/crates/effects/src/ocio.rs +++ b/crates/effects/src/ocio.rs @@ -617,7 +617,7 @@ pub fn load_file(src: &str) -> Option> { let parsed = if inline { parse_file(src, "") } else { - let ext = std::path::Path::new(src_t).extension().and_then(|e| e.to_str()).unwrap_or(""); + let ext = std::path::Path::new(src_t).extension().and_then(std::ffi::OsStr::to_str).unwrap_or(""); std::fs::read_to_string(src_t).ok().and_then(|t| parse_file(&t, ext)) } .map(Arc::new); diff --git a/crates/effects/src/roto.rs b/crates/effects/src/roto.rs index 4917cc23..354ef4a6 100644 --- a/crates/effects/src/roto.rs +++ b/crates/effects/src/roto.rs @@ -132,11 +132,11 @@ pub fn data(params: &Params) -> Arc { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { return d.clone(); } let d = Arc::new(RotoData::from_json(j)); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 64 { m.clear(); } @@ -247,11 +247,11 @@ fn cache() -> &'static Mutex { /// A cached segmentation (chain key, scale). pub fn cached(key: u64, scale: f64) -> Option> { - cache().lock().unwrap_or_else(|e| e.into_inner()).map.get(&(key, scale.to_bits())).cloned() + cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner).map.get(&(key, scale.to_bits())).cloned() } pub fn store(key: u64, scale: f64, seg: Arc) { - let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); + let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); let k = (key, scale.to_bits()); if c.map.contains_key(&k) { return; @@ -301,7 +301,7 @@ fn from_store(key: u64, scale: f64) -> Option> { /// Drop the cached segmentations of these chain keys (every scale). pub fn forget(keys: impl IntoIterator) { let keys: std::collections::HashSet = keys.into_iter().collect(); - let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); + let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); let gone: Vec<(u64, u64)> = c.map.keys().filter(|k| keys.contains(&k.0)).copied().collect(); for k in gone { if let Some(s) = c.map.remove(&k) { @@ -313,7 +313,7 @@ pub fn forget(keys: impl IntoIterator) { /// Drop every cached segmentation (Edit ▸ Purge). pub fn purge() { - let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); + let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); c.map.clear(); c.order.clear(); c.bytes = 0; @@ -532,11 +532,11 @@ fn frozen(params: &Params) -> Option> { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { return Some(d.clone()); } let d = Arc::new(FrozenCache::from_json(j)?); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 8 { m.clear(); } diff --git a/crates/effects/src/util.rs b/crates/effects/src/util.rs index 1527e221..ae55d095 100644 --- a/crates/effects/src/util.rs +++ b/crates/effects/src/util.rs @@ -537,7 +537,7 @@ impl SimCache { pub fn run(&self, key: u64, target: u64, init: impl FnOnce() -> S, mut step: impl FnMut(&mut S, u64)) -> std::sync::Arc { use std::sync::Arc; let start = { - let mut g = self.inner.lock().unwrap_or_else(|e| e.into_inner()); + let mut g = self.inner.lock().unwrap_or_else(std::sync::PoisonError::into_inner); let tick = g.iter().map(|e| e.used).max().unwrap_or(0) + 1; g.iter_mut().find(|e| e.key == key).and_then(|e| { e.used = tick; @@ -563,7 +563,7 @@ impl SimCache { } let out = Arc::new(st); fresh.push((target, out.clone())); - let mut g = self.inner.lock().unwrap_or_else(|e| e.into_inner()); + let mut g = self.inner.lock().unwrap_or_else(std::sync::PoisonError::into_inner); let tick = g.iter().map(|e| e.used).max().unwrap_or(0) + 1; let idx = match g.iter().position(|e| e.key == key) { Some(ix) => ix, diff --git a/crates/effects/src/warp_stab.rs b/crates/effects/src/warp_stab.rs index 595cb520..f850bdcf 100644 --- a/crates/effects/src/warp_stab.rs +++ b/crates/effects/src/warp_stab.rs @@ -191,11 +191,11 @@ fn analysis_cached(json: &str) -> Option<(u64, Arc)> { static C: OnceLock = OnceLock::new(); let key = fnv(json.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(a) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&key) { + if let Some(a) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key) { return Some((key, a.clone())); } let a = Arc::new(WarpAnalysis::from_json(json)?); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 8 { m.clear(); } @@ -294,7 +294,7 @@ pub fn store_summary(key: [u64; 2], summary: PlanSummary) { } fn keep_summary(key: (u64, u64), summary: Arc) { - let mut m = summaries().lock().unwrap_or_else(|e| e.into_inner()); + let mut m = summaries().lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 32 { m.clear(); } @@ -305,7 +305,7 @@ fn keep_summary(key: (u64, u64), summary: Arc) { /// cached (seconds for a long Subspace Warp clip). `None` when not analysed. pub fn summary(params: &Params) -> Option<([u64; 2], Arc)> { let (key, a, st) = plan_key(params)?; - let cached = summaries().lock().unwrap_or_else(|e| e.into_inner()).get(&key).cloned(); + let cached = summaries().lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key).cloned(); let sum = match cached { Some(s) => s, None => { @@ -333,7 +333,7 @@ pub fn summary_at(params: &Params, time: f64) -> Option<(usize, Arc pub fn cached_summary_at(params: &Params, time: f64) -> Option<(usize, Arc)> { let (key, a, _) = plan_key(params)?; let k = a.frame_at(time)?; - let sum = summaries().lock().unwrap_or_else(|e| e.into_inner()).get(&key).cloned(); + let sum = summaries().lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key).cloned(); let sum = match sum { Some(s) => s, None => { @@ -445,13 +445,13 @@ fn render(ctx: &EffectCtx, buf: Buf) -> Buf { } } if !local.is_empty() { - let mut n = need_m.lock().unwrap_or_else(|e| e.into_inner()); + let mut n = need_m.lock().unwrap_or_else(std::sync::PoisonError::into_inner); for (x, w) in local { n[y * ow as usize + x] = w; } } }); - let need = need_m.into_inner().unwrap_or_else(|e| e.into_inner()); + let need = need_m.into_inner().unwrap_or_else(std::sync::PoisonError::into_inner); if synth && need.iter().any(|w| *w > 0.0) { synthesize(ctx, &a, k, &src_of, &crop, sc, &mut out, &need); } diff --git a/crates/engine/src/commands/edit.rs b/crates/engine/src/commands/edit.rs index 3630efee..1e708ada 100644 --- a/crates/engine/src/commands/edit.rs +++ b/crates/engine/src/commands/edit.rs @@ -847,7 +847,7 @@ fn original_path(s: &Session) -> Option { /// importer takes. Anything else (a folder or app bundle, a script, a shortcut) is refused. pub(crate) fn openable_original(path: &str) -> std::result::Result<(), String> { let media = |p: &std::path::Path| { - let ext = p.extension().and_then(|e| e.to_str()).map(str::to_ascii_lowercase).unwrap_or_default(); + let ext = p.extension().and_then(std::ffi::OsStr::to_str).map(str::to_ascii_lowercase).unwrap_or_default(); crate::media_browser::kind_of(&p.to_string_lossy()).is_some_and(|k| k != "project") || matches!(ext.as_str(), "pdf" | "ai" | "eps") }; let name = std::path::Path::new(path).file_name().map(|n| n.to_string_lossy().into_owned()).unwrap_or_else(|| path.to_string()); diff --git a/crates/engine/src/commands/file.rs b/crates/engine/src/commands/file.rs index 0fea452d..b3922c7d 100644 --- a/crates/engine/src/commands/file.rs +++ b/crates/engine/src/commands/file.rs @@ -560,7 +560,7 @@ pub const DATA_EXTENSIONS: &[&str] = &["json", "csv", "tsv"]; /// A data footage item for `path` (JSON / CSV / TSV), `None` for other files. pub(crate) fn data_footage(services: &dyn crate::Services, path: &str) -> Option> { - let ext = std::path::Path::new(path).extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase(); + let ext = std::path::Path::new(path).extension().and_then(std::ffi::OsStr::to_str).unwrap_or("").to_ascii_lowercase(); if !DATA_EXTENSIONS.contains(&ext.as_str()) { return None; } diff --git a/crates/engine/src/commands/layer_menu.rs b/crates/engine/src/commands/layer_menu.rs index 0a044937..33d17bb4 100644 --- a/crates/engine/src/commands/layer_menu.rs +++ b/crates/engine/src/commands/layer_menu.rs @@ -708,7 +708,7 @@ const BUNDLE_EXTENSIONS: &[&str] = &[ /// Whether the system file manager would open folder `dir` as something other than a folder: a /// bundle (`Tool.app`), or a Windows folder with a `{CLSID}` extension. fn opens_as_bundle(dir: &std::path::Path) -> bool { - let ext = dir.extension().and_then(|e| e.to_str()).unwrap_or_default().to_ascii_lowercase(); + let ext = dir.extension().and_then(std::ffi::OsStr::to_str).unwrap_or_default().to_ascii_lowercase(); ext.starts_with('{') || BUNDLE_EXTENSIONS.contains(&ext.as_str()) } diff --git a/crates/engine/src/commands/paint.rs b/crates/engine/src/commands/paint.rs index 73f600b5..c02a1849 100644 --- a/crates/engine/src/commands/paint.rs +++ b/crates/engine/src/commands/paint.rs @@ -107,7 +107,7 @@ impl Default for PaintOptions { } fn norm(s: &str) -> String { - s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase() + s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase() } /// Index of `v` in `names` (by number or case/space-insensitive name). diff --git a/crates/engine/src/commands/relink.rs b/crates/engine/src/commands/relink.rs index 2d7c2ea1..d899decb 100644 --- a/crates/engine/src/commands/relink.rs +++ b/crates/engine/src/commands/relink.rs @@ -103,7 +103,7 @@ fn run(s: &mut Session, p: &Value) -> Result { } let supported = matches!(old.kind, FootageKind::Still | FootageKind::Sequence | FootageKind::Video | FootageKind::Audio) && old.layer.is_none() && old.page == 0; - let name = Path::new(&old.path).file_name().and_then(|n| n.to_str()).unwrap_or(""); + let name = Path::new(&old.path).file_name().and_then(std::ffi::OsStr::to_str).unwrap_or(""); let paths = index.get(name).cloned().unwrap_or_default(); let mut candidates = vec![]; let mut accepted = vec![]; diff --git a/crates/engine/src/mask_track.rs b/crates/engine/src/mask_track.rs index f85ba6b7..79c2b464 100644 --- a/crates/engine/src/mask_track.rs +++ b/crates/engine/src/mask_track.rs @@ -80,10 +80,10 @@ impl MaskMethod { } } pub fn from_name(s: &str) -> Option { - let n: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let n: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); MaskMethod::ALL .into_iter() - .find(|m| m.id().to_ascii_lowercase() == n || m.label().chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase() == n) + .find(|m| m.id().to_ascii_lowercase() == n || m.label().chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase() == n) } pub fn model(self) -> Model { match self { diff --git a/crates/engine/src/offload.rs b/crates/engine/src/offload.rs index ad2c0cde..135822d5 100644 --- a/crates/engine/src/offload.rs +++ b/crates/engine/src/offload.rs @@ -289,10 +289,10 @@ pub struct Inbox(Mutex>); impl Inbox { pub fn push(&self, r: WorkerReply) { - self.0.lock().unwrap_or_else(|e| e.into_inner()).push(r); + self.0.lock().unwrap_or_else(std::sync::PoisonError::into_inner).push(r); } pub fn take(&self) -> Vec { - std::mem::take(&mut *self.0.lock().unwrap_or_else(|e| e.into_inner())) + std::mem::take(&mut *self.0.lock().unwrap_or_else(std::sync::PoisonError::into_inner)) } } diff --git a/crates/engine/src/render_queue.rs b/crates/engine/src/render_queue.rs index 74b33315..27e9a7dc 100644 --- a/crates/engine/src/render_queue.rs +++ b/crates/engine/src/render_queue.rs @@ -110,7 +110,7 @@ pub struct JobShared { } pub(crate) fn lock(m: &Mutex) -> std::sync::MutexGuard<'_, T> { - m.lock().unwrap_or_else(|e| e.into_inner()) + m.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } impl JobShared { diff --git a/crates/engine/src/tests_proxy.rs b/crates/engine/src/tests_proxy.rs index 82cd1dcf..16e0cb00 100644 --- a/crates/engine/src/tests_proxy.rs +++ b/crates/engine/src/tests_proxy.rs @@ -20,7 +20,7 @@ use crate::render::{FootageSource, RenderOpts}; struct Synthetic; fn file_px(path: &str, x: u32, y: u32) -> [f32; 4] { - let name = std::path::Path::new(path).file_name().and_then(|n| n.to_str()).unwrap_or(""); + let name = std::path::Path::new(path).file_name().and_then(std::ffi::OsStr::to_str).unwrap_or(""); match name { "red16.png" => [1.0, 0.0, 0.0, 1.0], "blue8.png" => [0.0, 0.0, 1.0, 1.0], @@ -43,7 +43,7 @@ fn file_px(path: &str, x: u32, y: u32) -> [f32; 4] { } fn size_of(path: &str) -> (u32, u32) { - match std::path::Path::new(path).file_name().and_then(|n| n.to_str()).unwrap_or("") { + match std::path::Path::new(path).file_name().and_then(std::ffi::OsStr::to_str).unwrap_or("") { "red16.png" => (16, 16), "blue8.png" => (8, 8), "lines.mov" | "matte_black.png" | "matte_white.png" | "half.png" => (4, 4), diff --git a/crates/engine/src/tracking.rs b/crates/engine/src/tracking.rs index cfdd1244..434cdd8a 100644 --- a/crates/engine/src/tracking.rs +++ b/crates/engine/src/tracking.rs @@ -157,7 +157,7 @@ pub struct TrackShared { } pub(crate) fn lock(m: &Mutex) -> std::sync::MutexGuard<'_, T> { - m.lock().unwrap_or_else(|e| e.into_inner()) + m.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } /// A running (or finished, not yet polled) analysis. diff --git a/crates/engine/src/viewer.rs b/crates/engine/src/viewer.rs index 997c2023..6b6e5ce9 100644 --- a/crates/engine/src/viewer.rs +++ b/crates/engine/src/viewer.rs @@ -663,10 +663,10 @@ impl SimProfile { } pub fn parse(s: &str) -> Option { - let k: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let k: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); SimProfile::ALL .into_iter() - .find(|p| p.id().to_ascii_lowercase() == k || p.label().chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase() == k) + .find(|p| p.id().to_ascii_lowercase() == k || p.label().chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase() == k) .or(match k.as_str() { "off" => Some(SimProfile::None), "hdtv" | "bt709" => Some(SimProfile::Rec709), diff --git a/crates/export/src/pipeline.rs b/crates/export/src/pipeline.rs index 8dcee03e..9fd13147 100644 --- a/crates/export/src/pipeline.rs +++ b/crates/export/src/pipeline.rs @@ -247,7 +247,7 @@ impl<'a> Cx<'a> { } let img = self.crop_resize(img); if let Some(ft) = &self.frame_times { - ft.lock().unwrap_or_else(|e| e.into_inner()).push((i, t0.elapsed().as_secs_f64())); + ft.lock().unwrap_or_else(std::sync::PoisonError::into_inner).push((i, t0.elapsed().as_secs_f64())); } img } @@ -327,7 +327,7 @@ impl<'a> Cx<'a> { for dir in &self.job.options.overflow { let p = std::path::Path::new(dir).join(&name).to_string_lossy().to_string(); if q.has_room(&p, bytes) { - self.overflowed.lock().unwrap_or_else(|e| e.into_inner()).push(p.clone()); + self.overflowed.lock().unwrap_or_else(std::sync::PoisonError::into_inner).push(p.clone()); return p; } } @@ -351,7 +351,7 @@ impl<'a> Cx<'a> { Ok(r) => s.push_str(&format!("Result: Done ({} frames, {}×{}, {} bytes) in {seconds:.2} s\n", r.frames, r.width, r.height, r.bytes)), Err(e) => s.push_str(&format!("Result: Failed\nError: {e}\n")), } - let over = self.overflowed.lock().unwrap_or_else(|e| e.into_inner()); + let over = self.overflowed.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if !over.is_empty() { s.push_str(&format!("Storage overflow: {} file(s) written to overflow folders (first: {})\n", over.len(), over[0])); } @@ -366,7 +366,7 @@ impl<'a> Cx<'a> { } } if let (RenderLog::PlusPerFrameInfo, Some(ft), Some(c)) = (level, &self.frame_times, comp) { - let mut v = ft.lock().unwrap_or_else(|e| e.into_inner()).clone(); + let mut v = ft.lock().unwrap_or_else(std::sync::PoisonError::into_inner).clone(); v.sort_by_key(|(i, _)| *i); s.push_str("\nFrames:\n"); let f0 = self.job.settings.first_frame(c); diff --git a/crates/gpu/src/tests_deferred.rs b/crates/gpu/src/tests_deferred.rs index b6e43b55..e8778b62 100644 --- a/crates/gpu/src/tests_deferred.rs +++ b/crates/gpu/src/tests_deferred.rs @@ -30,7 +30,7 @@ pub(crate) fn deferred_gpu() -> Option<(&'static Gpu, std::sync::MutexGuard<'sta g }); let g = crate::tests::require_gpu("deferred gpu tests", g.as_ref())?; - Some((g, LOCK.lock().unwrap_or_else(|e| e.into_inner()))) + Some((g, LOCK.lock().unwrap_or_else(std::sync::PoisonError::into_inner))) } /// Footage with GPU effects around a CPU-only one, a solid with Glow, and a precomp whose diff --git a/crates/media/src/layered.rs b/crates/media/src/layered.rs index 0a70d1f7..055c3feb 100644 --- a/crates/media/src/layered.rs +++ b/crates/media/src/layered.rs @@ -36,7 +36,7 @@ pub fn vector_doc( } fn is_pdf_like(path: &str, bytes: &[u8]) -> bool { - let ext = std::path::Path::new(path).extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase(); + let ext = std::path::Path::new(path).extension().and_then(std::ffi::OsStr::to_str).unwrap_or("").to_ascii_lowercase(); effectcraft_pdf::sniff(bytes).is_some() && (effectcraft_pdf::EXTENSIONS.contains(&ext.as_str()) || bytes.starts_with(b"%PDF")) } diff --git a/crates/media/src/lib.rs b/crates/media/src/lib.rs index 04a9d95e..9b5b491a 100644 --- a/crates/media/src/lib.rs +++ b/crates/media/src/lib.rs @@ -80,7 +80,7 @@ pub fn is_importable(path: &std::path::Path) -> bool { } pub(crate) fn ext_of(path: &std::path::Path) -> String { - path.extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase() + path.extension().and_then(std::ffi::OsStr::to_str).unwrap_or("").to_ascii_lowercase() } /// The `image` crate format of a still: from its signature, else from its extension (Targa has diff --git a/crates/media/src/pool.rs b/crates/media/src/pool.rs index 4deefed3..7f602465 100644 --- a/crates/media/src/pool.rs +++ b/crates/media/src/pool.rs @@ -756,7 +756,7 @@ impl Inner { drop(c); return Ok(Arc::new(self.decode(&loc, footage)?)); } - c = self.done.wait(c).unwrap_or_else(|e| e.into_inner()); + c = self.done.wait(c).unwrap_or_else(std::sync::PoisonError::into_inner); } self.misses.fetch_add(1, Ordering::Relaxed); c.inflight.insert(loc.key.clone()); @@ -972,7 +972,7 @@ fn describe_problem(codec: &str, e: &MediaError) -> String { } fn lock(m: &Mutex) -> std::sync::MutexGuard<'_, T> { - m.lock().unwrap_or_else(|e| e.into_inner()) + m.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } #[cfg(test)] diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index e3cbf8f5..ceba1837 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -201,7 +201,7 @@ impl TimeDisplayStyle { } } pub fn parse(s: &str) -> Option { - let k: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let k: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); match k.as_str() { "timecode" => Some(TimeDisplayStyle::Timecode), "frames" => Some(TimeDisplayStyle::Frames), @@ -1234,7 +1234,7 @@ impl Footage { if self.kind != FootageKind::Data { return None; } - let ext = std::path::Path::new(&self.path).extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase(); + let ext = std::path::Path::new(&self.path).extension().and_then(std::ffi::OsStr::to_str).unwrap_or("").to_ascii_lowercase(); Some(match ext.as_str() { "csv" => "csv", "tsv" | "tab" => "tsv", diff --git a/crates/render/src/disk_cache.rs b/crates/render/src/disk_cache.rs index f867a614..4fa2e1cb 100644 --- a/crates/render/src/disk_cache.rs +++ b/crates/render/src/disk_cache.rs @@ -331,7 +331,7 @@ impl DiskCache { let Ok(files) = std::fs::read_dir(shard.path()) else { continue }; for f in files.flatten() { let p = f.path(); - let name = p.file_name().and_then(|n| n.to_str()).unwrap_or(""); + let name = p.file_name().and_then(std::ffi::OsStr::to_str).unwrap_or(""); if name.contains(".tmp") { // A writer that died mid-write; old temporaries are removed. if f.metadata().and_then(|m| m.modified()).is_ok_and(|t| t.elapsed().is_ok_and(|e| e.as_secs() > 600)) { diff --git a/crates/render/src/three_d/camera.rs b/crates/render/src/three_d/camera.rs index 5e1f983b..30873b6a 100644 --- a/crates/render/src/three_d/camera.rs +++ b/crates/render/src/three_d/camera.rs @@ -408,7 +408,7 @@ impl View3D { } } pub fn from_id(s: &str) -> Option { - let k: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let k: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); View3D::ALL.into_iter().find(|v| v.id().eq_ignore_ascii_case(&k) || v.label().replace(' ', "").eq_ignore_ascii_case(&k)) } pub fn is_ortho(self) -> bool { diff --git a/crates/script/src/socket.rs b/crates/script/src/socket.rs index 9d1f8798..6b2976dc 100644 --- a/crates/script/src/socket.rs +++ b/crates/script/src/socket.rs @@ -89,7 +89,7 @@ mod imp { Sock::Listener(_) => None, }; let entry = Arc::new(Entry { sock: Mutex::new(s), wake, closed: AtomicBool::new(false) }); - let mut t = table().lock().unwrap_or_else(|e| e.into_inner()); + let mut t = table().lock().unwrap_or_else(std::sync::PoisonError::into_inner); let id = t.next; t.next += 1; t.socks.insert(id, entry); @@ -98,12 +98,12 @@ mod imp { /// The socket `id`, if open. The table is locked only for the lookup. fn get(id: u32) -> Option> { - table().lock().unwrap_or_else(|e| e.into_inner()).socks.get(&id).cloned() + table().lock().unwrap_or_else(std::sync::PoisonError::into_inner).socks.get(&id).cloned() } /// Forget socket `id`; a call blocked on it fails at once. fn close(id: u32) { - let entry = table().lock().unwrap_or_else(|e| e.into_inner()).socks.remove(&id); + let entry = table().lock().unwrap_or_else(std::sync::PoisonError::into_inner).socks.remove(&id); if let Some(entry) = entry { entry.closed.store(true, Ordering::Release); if let Some(w) = &entry.wake { @@ -261,7 +261,7 @@ mod imp { _ => err("the socket is not open"), }; }; - let mut sock = entry.sock.lock().unwrap_or_else(|e| e.into_inner()); + let mut sock = entry.sock.lock().unwrap_or_else(std::sync::PoisonError::into_inner); // Recheck after locking: close or a failed mode transition may have retired it // while this caller waited with an Arc obtained from the table. if entry.closed.load(Ordering::Acquire) { diff --git a/crates/text/src/font_dirs.rs b/crates/text/src/font_dirs.rs index 0561d8f8..30694946 100644 --- a/crates/text/src/font_dirs.rs +++ b/crates/text/src/font_dirs.rs @@ -150,7 +150,9 @@ impl Reader<'_> { let mut files: Vec = rd .flatten() .map(|e| e.path()) - .filter(|p| p.file_name().and_then(|n| n.to_str()).is_some_and(|n| n.ends_with(".conf") && n.starts_with(|c: char| c.is_ascii_digit()))) + .filter(|p| { + p.file_name().and_then(std::ffi::OsStr::to_str).is_some_and(|n| n.ends_with(".conf") && n.starts_with(|c: char| c.is_ascii_digit())) + }) .collect(); files.sort(); for f in files { diff --git a/crates/text/src/fonts.rs b/crates/text/src/fonts.rs index 724fc4aa..e20ffcbd 100644 --- a/crates/text/src/fonts.rs +++ b/crates/text/src/fonts.rs @@ -116,7 +116,7 @@ fn walk(dir: &std::path::Path, depth: u32, out: &mut Vec) { if depth < 8 { walk(&p, depth + 1, out); } - } else if p.extension().and_then(|x| x.to_str()).is_some_and(|x| matches!(x.to_ascii_lowercase().as_str(), "ttf" | "otf" | "ttc" | "otc")) { + } else if p.extension().and_then(std::ffi::OsStr::to_str).is_some_and(|x| matches!(x.to_ascii_lowercase().as_str(), "ttf" | "otf" | "ttc" | "otc")) { out.push(p); } } @@ -319,7 +319,7 @@ fn push(db: &mut Db, info: FaceInfo) -> FaceId { /// added. pub fn add_source(src: &dyn FontSource) -> usize { let faces = src.faces(); - let mut d = db().write().unwrap_or_else(|e| e.into_inner()); + let mut d = db().write().unwrap_or_else(std::sync::PoisonError::into_inner); let mut n = 0; for f in faces { let dup = d.faces.iter().any(|g| g.info.family.eq_ignore_ascii_case(&f.family) && g.info.style.eq_ignore_ascii_case(&f.style)); @@ -329,7 +329,7 @@ pub fn add_source(src: &dyn FontSource) -> usize { } } // A new face can belong to one of a script's usual families. - family_faces_cache().write().unwrap_or_else(|e| e.into_inner()).clear(); + family_faces_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).clear(); n } @@ -337,9 +337,9 @@ pub fn add_source(src: &dyn FontSource) -> usize { pub fn add_font_data(data: Vec) -> Vec { let data = Arc::new(data); let names = read_faces_bytes(&data); - let mut d = db().write().unwrap_or_else(|e| e.into_inner()); + let mut d = db().write().unwrap_or_else(std::sync::PoisonError::into_inner); let ids = names.into_iter().map(|n| push(&mut d, info_from(n, FaceData::Shared(data.clone()), "user"))).collect(); - family_faces_cache().write().unwrap_or_else(|e| e.into_inner()).clear(); + family_faces_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).clear(); ids } @@ -353,21 +353,21 @@ pub fn scan_system() -> usize { if system_scanned() { return 0; } - let _scan = SCAN.lock().unwrap_or_else(|e| e.into_inner()); + let _scan = SCAN.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if system_scanned() { return 0; } let n = if cfg!(target_arch = "wasm32") { 0 } else { add_source(&DirectorySource::system()) }; - db().write().unwrap_or_else(|e| e.into_inner()).scanned = true; + db().write().unwrap_or_else(std::sync::PoisonError::into_inner).scanned = true; n } /// Scan the system font folders again, adding fonts installed since the last scan (faces already /// known are kept, so font ids stay valid). Returns the number of faces added. pub fn rescan_system() -> usize { - let _scan = SCAN.lock().unwrap_or_else(|e| e.into_inner()); + let _scan = SCAN.lock().unwrap_or_else(std::sync::PoisonError::into_inner); let n = if cfg!(target_arch = "wasm32") { 0 } else { add_source(&DirectorySource::system()) }; - db().write().unwrap_or_else(|e| e.into_inner()).scanned = true; + db().write().unwrap_or_else(std::sync::PoisonError::into_inner).scanned = true; n } @@ -388,12 +388,12 @@ pub fn scan_system_in_background() { } pub fn system_scanned() -> bool { - db().read().unwrap_or_else(|e| e.into_inner()).scanned + db().read().unwrap_or_else(std::sync::PoisonError::into_inner).scanned } /// A face by id (panics never: unknown ids give the default face). pub fn face(id: FaceId) -> Arc { - let d = db().read().unwrap_or_else(|e| e.into_inner()); + let d = db().read().unwrap_or_else(std::sync::PoisonError::into_inner); // The bundled fonts are compiled in and always parse (`tests::bundled_families_and_resolution` checks them), so // the database is never empty. #[allow(clippy::expect_used)] @@ -402,7 +402,7 @@ pub fn face(id: FaceId) -> Arc { /// All faces (bundled first). pub fn all_faces() -> Vec> { - db().read().unwrap_or_else(|e| e.into_inner()).faces.clone() + db().read().unwrap_or_else(std::sync::PoisonError::into_inner).faces.clone() } /// Family names in the fonts' own languages: English family → native family (only families @@ -743,15 +743,15 @@ static REQUESTED_CJK_LOCALE: RwLock> = RwLock::new(None); pub fn set_cjk_locale(tag: &str) { let tag = tag.trim().to_ascii_lowercase(); let requested = if tag.is_empty() || tag == "c" || tag == "posix" { None } else { Some(tag) }; - *REQUESTED_CJK_LOCALE.write().unwrap_or_else(|e| e.into_inner()) = requested; + *REQUESTED_CJK_LOCALE.write().unwrap_or_else(std::sync::PoisonError::into_inner) = requested; // The order of the CJK families follows the language, so a change of language drops the cached // fallbacks. - fallback_cache().write().unwrap_or_else(|e| e.into_inner()).clear(); - family_faces_cache().write().unwrap_or_else(|e| e.into_inner()).clear(); + fallback_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).clear(); + family_faces_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).clear(); } fn requested_cjk_locale() -> Option { - REQUESTED_CJK_LOCALE.read().unwrap_or_else(|e| e.into_inner()).clone() + REQUESTED_CJK_LOCALE.read().unwrap_or_else(std::sync::PoisonError::into_inner).clone() } /// The CJK locale to use: [`set_cjk_locale`] when the host asked for one, otherwise the locale @@ -981,7 +981,7 @@ fn fallback_with_locale(c: char, prefer: FaceId, locale: impl FnOnce() -> CjkLoc } } let key = (c as u32 >> 8, prefer); - if let Some(cached) = fallback_cache().read().unwrap_or_else(|e| e.into_inner()).get(&key).copied() { + if let Some(cached) = fallback_cache().read().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key).copied() { match cached { Some(id) if face(id).has_char(c) => return id, Some(_) => {} @@ -992,7 +992,7 @@ fn fallback_with_locale(c: char, prefer: FaceId, locale: impl FnOnce() -> CjkLoc scan_system(); } let found = system_fallback(c, &p.info.style); - fallback_cache().write().unwrap_or_else(|e| e.into_inner()).insert(key, found); + fallback_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).insert(key, found); found.unwrap_or(prefer) } @@ -1000,7 +1000,7 @@ fn fallback_with_locale(c: char, prefer: FaceId, locale: impl FnOnce() -> CjkLoc /// for `script`, in the order they are tried, each in the style of `prefer`. For CJK, the other CJK /// languages' families follow in the locale's order. fn family_faces(script: FallbackScript, prefer: &Face, locale: CjkLocale) -> Arc> { - if let Some(faces) = family_faces_cache().read().unwrap_or_else(|e| e.into_inner()).get(&(script, prefer.id, locale)) { + if let Some(faces) = family_faces_cache().read().unwrap_or_else(std::sync::PoisonError::into_inner).get(&(script, prefer.id, locale)) { return faces.clone(); } let order: Vec = match script { @@ -1016,7 +1016,7 @@ fn family_faces(script: FallbackScript, prefer: &Face, locale: CjkLocale) -> Arc let style = &prefer.info.style; let faces: Arc> = Arc::new(order.into_iter().flat_map(|s| families_for(s, locale)).filter_map(|fam| resolve_in(fam, style)).map(|r| r.face).collect()); - family_faces_cache().write().unwrap_or_else(|e| e.into_inner()).insert((script, prefer.id, locale), faces.clone()); + family_faces_cache().write().unwrap_or_else(std::sync::PoisonError::into_inner).insert((script, prefer.id, locale), faces.clone()); faces } diff --git a/crates/text/src/layout.rs b/crates/text/src/layout.rs index 7ca5bd13..0730e444 100644 --- a/crates/text/src/layout.rs +++ b/crates/text/src/layout.rs @@ -399,7 +399,7 @@ enum Form { pub fn feature_substitutes(face: FaceId, tag: &[u8; 4], c: char) -> bool { static C: OnceLock>> = OnceLock::new(); let cache = C.get_or_init(Default::default); - if let Some(v) = cache.lock().unwrap_or_else(|e| e.into_inner()).get(&(face, *tag, c)) { + if let Some(v) = cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&(face, *tag, c)) { return *v; } let f = fonts::face(face); @@ -419,7 +419,7 @@ pub fn feature_substitutes(face: FaceId, tag: &[u8; 4], c: char) -> bool { } _ => false, }; - let mut m = cache.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = cache.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 100_000 { m.clear(); } @@ -1123,12 +1123,12 @@ pub fn layout_rich(text: &str, runs: &[(Range, TextStyle)], paras: &[Para let key = h.finish(); static CLOCK: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); let now = CLOCK.fetch_add(1, std::sync::atomic::Ordering::Relaxed); - if let Some(e) = cache().lock().unwrap_or_else(|e| e.into_inner()).get_mut(&key) { + if let Some(e) = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner).get_mut(&key) { e.0 = now; return e.1.clone(); } let l = Arc::new(layout_rich_uncached(text, runs, paras)); - let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); + let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); if c.len() >= 512 { // evict the oldest quarter let mut ages: Vec = c.values().map(|v| v.0).collect(); diff --git a/crates/text/src/lib.rs b/crates/text/src/lib.rs index 18716752..35e7ecc0 100644 --- a/crates/text/src/lib.rs +++ b/crates/text/src/lib.rs @@ -54,7 +54,7 @@ impl OutlinePen for Pen { pub(crate) fn outline_units(face: FaceId, gid: u32) -> Option> { static C: OnceLock>>>> = OnceLock::new(); let c = C.get_or_init(Default::default); - if let Some(v) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&(face, gid)) { + if let Some(v) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&(face, gid)) { return v.clone(); } let f = fonts::face(face); @@ -64,7 +64,7 @@ pub(crate) fn outline_units(face: FaceId, gid: u32) -> Option> { g.draw(DrawSettings::unhinted(Size::unscaled(), LocationRef::default()), &mut pen).ok()?; Some(Arc::new(pen.0)) }); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 50_000 { m.clear(); } diff --git a/crates/text/src/variable.rs b/crates/text/src/variable.rs index bf4fde39..55934335 100644 --- a/crates/text/src/variable.rs +++ b/crates/text/src/variable.rs @@ -36,7 +36,7 @@ pub fn intern(coords: &[(String, f32)]) -> u32 { if key.windows(2).any(|w| w[0].0 == w[1].0) { return 0; } - let mut t = table().lock().unwrap_or_else(|e| e.into_inner()); + let mut t = table().lock().unwrap_or_else(std::sync::PoisonError::into_inner); if let Some(id) = t.by_coords.get(&key) { return *id; } @@ -55,7 +55,7 @@ pub fn coords(id: u32) -> Arc> { if id == 0 { return Arc::new(Vec::new()); } - table().lock().unwrap_or_else(|e| e.into_inner()).values.get(id as usize - 1).cloned().unwrap_or_default() + table().lock().unwrap_or_else(std::sync::PoisonError::into_inner).values.get(id as usize - 1).cloned().unwrap_or_default() } fn table() -> &'static Mutex { @@ -109,7 +109,7 @@ pub fn outline_units_at(face: FaceId, gid: u32, coords: &[(String, f32)]) -> Opt let c = C.get_or_init(Default::default); // Quantise to 1/100 of a unit so animation frames reuse outlines. let key: Key = (face, gid, coords.iter().map(|(t, v)| (t.clone(), (v * 100.0).round() as i32)).collect()); - if let Some(v) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&key) { + if let Some(v) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&key) { return v.clone(); } let f = fonts::face(face); @@ -120,7 +120,7 @@ pub fn outline_units_at(face: FaceId, gid: u32, coords: &[(String, f32)]) -> Opt g.draw(DrawSettings::unhinted(Size::unscaled(), LocationRef::from(&loc)), &mut pen).ok()?; Some(Arc::new(pen.0)) }); - let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); if m.len() > 20_000 { m.clear(); } diff --git a/crates/ui-egui/src/panels/home.rs b/crates/ui-egui/src/panels/home.rs index fcfd0170..fa35d7c8 100644 --- a/crates/ui-egui/src/panels/home.rs +++ b/crates/ui-egui/src/panels/home.rs @@ -127,7 +127,7 @@ pub fn format_size(bytes: u64) -> String { /// The Kind column: what a recent file is, by its extension, in the interface language. fn kind_of(path: &str) -> &'static str { - tr(match std::path::Path::new(path).extension().and_then(|e| e.to_str()).map(str::to_ascii_lowercase).as_deref() { + tr(match std::path::Path::new(path).extension().and_then(std::ffi::OsStr::to_str).map(str::to_ascii_lowercase).as_deref() { Some("ecproj") => "EffectCraft project", Some("aep" | "aepx") => "After Effects project", Some("json" | "lottie") => "Lottie animation", diff --git a/xtask/src/main.rs b/xtask/src/main.rs index e4ddaef7..da8026d7 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -176,7 +176,7 @@ fn repo_files() -> Result, String> { } fn is_asset(path: &str) -> bool { - std::path::Path::new(path).extension().and_then(|e| e.to_str()).is_some_and(|e| ASSET_EXT.contains(&e.to_ascii_lowercase().as_str())) + std::path::Path::new(path).extension().and_then(std::ffi::OsStr::to_str).is_some_and(|e| ASSET_EXT.contains(&e.to_ascii_lowercase().as_str())) } fn assets() -> Result<(), String> { @@ -384,7 +384,7 @@ fn serve_dir(dir: &std::path::Path, port: u16) -> Result<(), String> { Ok(b) => ("200 OK", b), Err(_) => ("404 Not Found", b"not found".to_vec()), }; - let mime = match file.extension().and_then(|e| e.to_str()).unwrap_or("") { + let mime = match file.extension().and_then(std::ffi::OsStr::to_str).unwrap_or("") { "html" => "text/html; charset=utf-8", "js" => "text/javascript", "wasm" => "application/wasm", From c07604563e039e143fe2561976d8da7b4febbcf8 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sat, 24 Oct 2026 08:45:39 +0000 Subject: [PATCH 2/2] sonar: leave the duplicated cache blocks in object_matte and roto alone (new-code duplication gate) Co-Authored-By: Claude Sonnet 5.5 --- crates/effects/src/object_matte.rs | 4 ++-- crates/effects/src/roto.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/effects/src/object_matte.rs b/crates/effects/src/object_matte.rs index a12d3332..d98ec73a 100644 --- a/crates/effects/src/object_matte.rs +++ b/crates/effects/src/object_matte.rs @@ -315,11 +315,11 @@ fn frozen_cache(j: &str) -> Option> { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { return Some(d.clone()); } let d = Arc::new(FrozenCache::from_json(j)?); - let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); if m.len() > 8 { m.clear(); } diff --git a/crates/effects/src/roto.rs b/crates/effects/src/roto.rs index 354ef4a6..4917cc23 100644 --- a/crates/effects/src/roto.rs +++ b/crates/effects/src/roto.rs @@ -132,11 +132,11 @@ pub fn data(params: &Params) -> Arc { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { return d.clone(); } let d = Arc::new(RotoData::from_json(j)); - let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); if m.len() > 64 { m.clear(); } @@ -247,11 +247,11 @@ fn cache() -> &'static Mutex { /// A cached segmentation (chain key, scale). pub fn cached(key: u64, scale: f64) -> Option> { - cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner).map.get(&(key, scale.to_bits())).cloned() + cache().lock().unwrap_or_else(|e| e.into_inner()).map.get(&(key, scale.to_bits())).cloned() } pub fn store(key: u64, scale: f64, seg: Arc) { - let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); let k = (key, scale.to_bits()); if c.map.contains_key(&k) { return; @@ -301,7 +301,7 @@ fn from_store(key: u64, scale: f64) -> Option> { /// Drop the cached segmentations of these chain keys (every scale). pub fn forget(keys: impl IntoIterator) { let keys: std::collections::HashSet = keys.into_iter().collect(); - let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); let gone: Vec<(u64, u64)> = c.map.keys().filter(|k| keys.contains(&k.0)).copied().collect(); for k in gone { if let Some(s) = c.map.remove(&k) { @@ -313,7 +313,7 @@ pub fn forget(keys: impl IntoIterator) { /// Drop every cached segmentation (Edit ▸ Purge). pub fn purge() { - let mut c = cache().lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut c = cache().lock().unwrap_or_else(|e| e.into_inner()); c.map.clear(); c.order.clear(); c.bytes = 0; @@ -532,11 +532,11 @@ fn frozen(params: &Params) -> Option> { let mut h = 0xcbf2_9ce4_8422_2325; fnv(&mut h, j.as_bytes()); let c = C.get_or_init(Default::default); - if let Some(d) = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner).get(&h) { + if let Some(d) = c.lock().unwrap_or_else(|e| e.into_inner()).get(&h) { return Some(d.clone()); } let d = Arc::new(FrozenCache::from_json(j)?); - let mut m = c.lock().unwrap_or_else(std::sync::PoisonError::into_inner); + let mut m = c.lock().unwrap_or_else(|e| e.into_inner()); if m.len() > 8 { m.clear(); }