From ac222e818b5f13c19b623904f99a648003570943 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 4 Oct 2026 14:23:06 -0400 Subject: [PATCH] Never crash: edit and xfdf have no expect calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - edit: the substitute font name is a `&str` constant, so there's no `from_utf8(..).expect`. Paragraph grouping uses `let … else` / `if let` chains, and the reuse-font path takes the metrics with `filter` instead of `expect("checked")`. - xfdf: a comment key that vanished between listing and lookup is skipped. Both crates now deny the panic lints. Adds the root clippy.toml (identical to #11) so tests may still unwrap. Co-Authored-By: Claude Opus 5.5 --- clippy.toml | 4 ++++ crates/edit/src/lib.rs | 2 ++ crates/edit/src/text.rs | 18 +++++++++++------- crates/xfdf/src/lib.rs | 5 ++++- 4 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 clippy.toml 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/edit/src/lib.rs b/crates/edit/src/lib.rs index 9d9ddcc1..d18bd692 100644 --- a/crates/edit/src/lib.rs +++ b/crates/edit/src/lib.rs @@ -12,6 +12,8 @@ //! //! Text uses standard Helvetica (WinAnsi) added to the page resources as `/PCHelv`. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] + use printcraft_cos::{Dict, Document, Object, Stream}; use printcraft_fonts::{helvetica_width, literal, win_ansi}; diff --git a/crates/edit/src/text.rs b/crates/edit/src/text.rs index ed0fdecb..2ae195b1 100644 --- a/crates/edit/src/text.rs +++ b/crates/edit/src/text.rs @@ -400,7 +400,8 @@ pub fn text_lines(doc: &Document, page: usize) -> Result, EditErro type Encoder = Box Option>>; /// The substitute font's resource name. -const SUBSTITUTE: &[u8] = b"PCEdHelv"; +const SUBSTITUTE_NAME: &str = "PCEdHelv"; +const SUBSTITUTE: &[u8] = SUBSTITUTE_NAME.as_bytes(); /// Replace the text of line `line` (an index into [`text_lines`]) on `page` with `text`. pub fn replace_line(doc: &mut Document, page: usize, line: usize, text: &str) -> Result { @@ -440,7 +441,7 @@ pub fn replace_line(doc: &mut Document, page: usize, line: usize, text: &str) -> } // The size in text space: the current Tf's size. let size = font_size_before(&ops, first).unwrap_or(target.size); - replacement.push(Op::new("Tf", vec![Object::name(std::str::from_utf8(SUBSTITUTE).expect("ascii")), printcraft_content::num(size)])); + replacement.push(Op::new("Tf", vec![Object::name(SUBSTITUTE_NAME), printcraft_content::num(size)])); replacement.push(Op::new("Tj", vec![Object::String(PdfString::literal(win))])); replacement.push(Op::new("Tf", vec![Object::name(&target.font), printcraft_content::num(size)])); substituted = Some("Helvetica".to_string()); @@ -506,7 +507,8 @@ fn group_blocks(lines: &[TextLine]) -> Vec { for (i, l) in lines.iter().enumerate() { let joins = i > 0 && blocks.last().is_some_and(|b| { - let prev = &lines[*b.lines.last().expect("non-empty")]; + let Some(&p) = b.lines.last() else { return false }; + let prev = &lines[p]; let g = prev.origin.baseline - l.origin.baseline; prev.stream == l.stream && prev.font == l.font @@ -516,8 +518,11 @@ fn group_blocks(lines: &[TextLine]) -> Vec { && g < l.size * 2.5 && gap.is_none_or(|first| (g - first).abs() < first * 0.2) }); - if joins && let Some(b) = blocks.last_mut() { - let prev = &lines[*b.lines.last().expect("non-empty")]; + if joins + && let Some(b) = blocks.last_mut() + && let Some(&p) = b.lines.last() + { + let prev = &lines[p]; gap.get_or_insert(prev.origin.baseline - l.origin.baseline); if b.text.ends_with('-') { b.text.pop(); @@ -643,8 +648,7 @@ pub fn rewrite_block(doc: &mut Document, page: usize, block: usize, text: Option let wrapped = wrap(&text, width + 0.5, advance); let mut substituted = None; let new_font = !reuse; - let (show_font, encode): (String, Encoder) = if reuse { - let m = metrics.clone().expect("checked"); + let (show_font, encode): (String, Encoder) = if let Some(m) = metrics.clone().filter(|_| reuse) { (font_name.clone(), Box::new(move |s: &str| m.encode(s))) } else { let win = printcraft_fonts::win_ansi(&text); diff --git a/crates/xfdf/src/lib.rs b/crates/xfdf/src/lib.rs index 1af19e95..1ccbeab4 100644 --- a/crates/xfdf/src/lib.rs +++ b/crates/xfdf/src/lib.rs @@ -9,6 +9,8 @@ //! Import merges: a comment whose name (`/NM`) already exists on its page replaces it; field //! values go through the form's own checks (formats, validation) and recalculate. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] + use std::collections::HashMap; use std::fmt::Write as _; @@ -389,7 +391,8 @@ pub fn export_fdf(doc: &Document, comments: bool, fields: bool, file: &str) -> V } let keys: Vec> = d.iter().filter(|(_, v)| matches!(v, Object::Ref(_))).map(|(k, _)| k.clone()).collect(); for k in keys { - let v = (*doc.resolve(d.get(&k).expect("listed"))).clone(); + let Some(o) = d.get(&k) else { continue }; + let v = (*doc.resolve(o)).clone(); if matches!(v, Object::Stream(_)) { d.remove(&k); } else {