diff --git a/apps/vectorcraft-cli/src/perf.rs b/apps/vectorcraft-cli/src/perf.rs index 3ab22a11..40621d55 100644 --- a/apps/vectorcraft-cli/src/perf.rs +++ b/apps/vectorcraft-cli/src/perf.rs @@ -43,7 +43,9 @@ pub fn synthetic(n: usize) -> Document { if i % 3 == 1 { node.opacity = 0.8; } - d.insert(Some(l), usize::MAX, node).expect("insert"); + if d.insert(Some(l), usize::MAX, node).is_err() { + break; + } } d } @@ -122,8 +124,17 @@ pub fn run(args: &[String]) -> Result<(), String> { rows.push(("hit test (per click)", hits, 2.0)); let mut bytes = vec![]; + let mut failed: Option = None; rows.push(("save .vectorcraft", median_ms(3, || bytes = vectorcraft_format::save_file(&doc)), 300.0)); - rows.push(("open .vectorcraft", median_ms(3, || drop(vectorcraft_format::load(&bytes).expect("load"))), 300.0)); + rows.push(( + "open .vectorcraft", + median_ms(3, || { + if let Err(e) = vectorcraft_format::load(&bytes) { + failed = Some(format!("open .vectorcraft: {e}")); + } + }), + 300.0, + )); let svg_opts = vectorcraft_svg::ExportOptions::default(); rows.push(("export SVG", median_ms(3, || drop(vectorcraft_svg::export(&doc, &svg_opts))), 500.0)); @@ -131,10 +142,14 @@ pub fn run(args: &[String]) -> Result<(), String> { let unite = median_ms(3, || { let mut s = vectorcraft_engine::Session::new(); s.add_document(synthetic(1000), None); - s.execute("select.all", &json!({})).expect("select"); - s.execute("object.pathfinder.unite", &json!({})).expect("unite"); + if let Err(e) = s.execute("select.all", &json!({})).and_then(|_| s.execute("object.pathfinder.unite", &json!({}))) { + failed = Some(format!("Pathfinder Unite: {e}")); + } }); rows.push(("Pathfinder Unite, 1,000 paths", unite, 150.0)); + if let Some(e) = failed { + return Err(e); + } let mut over = 0; println!(" {:<40} {:>10} {:>10}", "", "measured", "budget"); diff --git a/apps/vectorcraft-web/src/main.rs b/apps/vectorcraft-web/src/main.rs index 945f83d4..903d2be6 100644 --- a/apps/vectorcraft-web/src/main.rs +++ b/apps/vectorcraft-web/src/main.rs @@ -12,6 +12,7 @@ //! - dropped files are read asynchronously by `web::WebShell` and delivered through the inbox. //! //! URL query flag: `?webgl` forces the WebGL2 backend instead of WebGPU. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #[cfg(target_arch = "wasm32")] mod web; diff --git a/apps/vectorcraft/src/main.rs b/apps/vectorcraft/src/main.rs index 8d35e65d..7f6eb44b 100644 --- a/apps/vectorcraft/src/main.rs +++ b/apps/vectorcraft/src/main.rs @@ -5,6 +5,7 @@ //! `--control ` (or `VECTORCRAFT_CONTROL_PORT`) starts a localhost JSON-lines control server: //! `{"id":1,"method":"ui.inspect","params":{}}` → `{"id":1,"ok":true,"result":…}`. //! See `vectorcraft_ui_egui::control` for the methods. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] mod control_server; #[cfg(target_os = "macos")] diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..4b6c79f5 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,4 @@ +allow-unwrap-in-tests = true +allow-expect-in-tests = true +allow-panic-in-tests = true +allow-indexing-slicing-in-tests = true diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 7bb4c3d2..a8ef7179 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -107,7 +107,7 @@ pub fn fit(app: &mut VectorcraftApp, how: &str) { _ => st.doc.artboards.first().map(|a| a.rect), }; let Some(target) = target else { return }; - let v = app.view_mut().unwrap(); + let Some(v) = app.view_mut() else { return }; v.center = target.center(); v.fitted = true; if how == "view.actualSize" { diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 673c65bd..d9c9799c 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -4,6 +4,7 @@ //! (view/window) here and everything else to the engine. The same entry point serves menus, //! shortcuts, the ⌘K palette and the control channel ([`control`]). #![forbid(unsafe_code)] +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] mod brand; pub mod canvas; diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 4fd22900..5411ec2f 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -1574,7 +1574,14 @@ pub fn pretty_shortcut(s: &str) -> String { if cfg!(target_os = "macos") { let mut mods = String::new(); let parts: Vec<&str> = s.split('+').collect(); - let (key, ms) = if s.ends_with("++") { ("+", &parts[..parts.len() - 2]) } else { (*parts.last().unwrap(), &parts[..parts.len() - 1]) }; + let (key, ms) = if s.ends_with("++") { + ("+", parts.get(..parts.len().saturating_sub(2)).unwrap_or_default()) + } else { + match parts.split_last() { + Some((key, ms)) => (*key, ms), + None => (s, &[][..]), + } + }; for m in ["Ctrl", "Alt", "Shift", "Cmd"] { if ms.contains(&m) { mods.push_str(match m { diff --git a/crates/ui-egui/src/panels/layers.rs b/crates/ui-egui/src/panels/layers.rs index 8988d335..699cbbbf 100644 --- a/crates/ui-egui/src/panels/layers.rs +++ b/crates/ui-egui/src/panels/layers.rs @@ -275,7 +275,7 @@ fn row( } if has_children && expanded.contains(&n.id.0) { - for (i, c) in n.children().unwrap().iter().enumerate().rev() { + for (i, c) in n.children().map_or(&[][..], Vec::as_slice).iter().enumerate().rev() { row(ui, doc, c, depth + 1, i == 0 && n.clips(), sel, current, expanded, actions, t); } } diff --git a/crates/ui-egui/src/panels/swatches.rs b/crates/ui-egui/src/panels/swatches.rs index 12f6fb42..550bf757 100644 --- a/crates/ui-egui/src/panels/swatches.rs +++ b/crates/ui-egui/src/panels/swatches.rs @@ -676,7 +676,9 @@ pub(crate) fn tile_grid<'a, T>(ui: &mut Ui, items: &'a [T], view: View, is_folde if len == per_row || (len > 0 && is_folder(e)) { rows.push(vec![]); } - rows.last_mut().expect("a row").push(e); + if let Some(row) = rows.last_mut() { + row.push(e); + } } let mut out = Vec::with_capacity(items.len()); for row in rows {