diff --git a/crates/ac3/src/lib.rs b/crates/ac3/src/lib.rs index ab34ad90..dfb53c5f 100644 --- a/crates/ac3/src/lib.rs +++ b/crates/ac3/src/lib.rs @@ -13,6 +13,8 @@ //! //! E-AC-3 (bsid 11-16) is recognised and refused. +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] + mod tables; use std::sync::OnceLock; @@ -1029,7 +1031,7 @@ impl Decoder { /// Coded channel order (Table 5.8) → WAV / SMPTE order: fronts L R C, LFE, surrounds. fn wav_order(mut pcm: Vec>, acmod: usize, lfeon: bool) -> Vec> { let nf = NFCHANS[acmod]; - let lfe = lfeon.then(|| pcm.pop().expect("lfe")); + let lfe = if lfeon { pcm.pop() } else { None }; let mut fbw = pcm; // acmod 3, 5, 7 code L C R …: move C after R if acmod & 1 == 1 && acmod != 1 { diff --git a/crates/audio-dsp/src/channels.rs b/crates/audio-dsp/src/channels.rs index 37dc1956..cda0f0c2 100644 --- a/crates/audio-dsp/src/channels.rs +++ b/crates/audio-dsp/src/channels.rs @@ -123,7 +123,7 @@ pub fn matrix(from: Layout, to: Layout, mixdown: Mixdown) -> Vec> { let (ni, no) = (from.channels(), to.channels()); let mut m = vec![vec![0.0f32; ni]; no]; match (from, to) { - (a, b) if a == b => { + (Layout::Mono, Layout::Mono) | (Layout::Stereo, Layout::Stereo) | (Layout::Surround51, Layout::Surround51) => { for (i, row) in m.iter_mut().enumerate() { row[i] = 1.0; } @@ -159,7 +159,6 @@ pub fn matrix(from: Layout, to: Layout, mixdown: Mixdown) -> Vec> { m[1][LFE] = K; } } - _ => unreachable!("all layout pairs are covered"), } m } diff --git a/crates/audio-dsp/src/lib.rs b/crates/audio-dsp/src/lib.rs index 491a9e97..739abeca 100644 --- a/crates/audio-dsp/src/lib.rs +++ b/crates/audio-dsp/src/lib.rs @@ -16,6 +16,8 @@ //! denormals never appear (no FTZ/DAZ CPU flags needed, which keeps the crate `unsafe`-free and //! portable to wasm). +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] + pub mod biquad; pub mod channels; pub mod design; @@ -169,12 +171,11 @@ impl ParamValues { pub(crate) fn get(&self, id: &str) -> Option { self.index_of(id).map(|i| self.values[i]) } - /// Value of a parameter that is known to exist (panics otherwise — programming error). + /// Value of a parameter that is known to exist (0 otherwise — a programming error caught by + /// debug builds). pub(crate) fn v(&self, id: &str) -> f32 { - match self.get(id) { - Some(v) => v, - None => panic!("unknown parameter {id}"), - } + debug_assert!(self.get(id).is_some(), "unknown parameter {id}"); + self.get(id).unwrap_or(0.0) } pub(crate) fn on(&self, id: &str) -> bool { self.v(id) >= 0.5 diff --git a/crates/dnx/README.md b/crates/dnx/README.md index cf51f71f..596ea9fa 100644 --- a/crates/dnx/README.md +++ b/crates/dnx/README.md @@ -38,7 +38,7 @@ let f = decode_frame_with(&sample, &DecodeOptions { threads: false, ..Default::d let hdr: FrameHeader = probe(&sample)?; // cid, raster, depth, chroma… let name = cid_name(hdr.cid); // "DNxHR HQX", "DNxHD 1080i 8-bit (CID 1242)" -let mut enc = Encoder::new(Profile::Hq, 1920, 1080); // or Encoder::with_config(EncoderConfig { .. }) +let mut enc = Encoder::new(Profile::Hq, 1920, 1080)?; // or Encoder::with_config(EncoderConfig { .. }) let sample: Vec = enc.encode(&frame)?; // exactly enc.frame_size() bytes (CBR) ``` diff --git a/crates/dnx/src/dct.rs b/crates/dnx/src/dct.rs index 1d1603bc..53248290 100644 --- a/crates/dnx/src/dct.rs +++ b/crates/dnx/src/dct.rs @@ -19,8 +19,7 @@ pub(crate) fn idct8x8(block: &mut [f32; 64]) { let mut nz = [false; 8]; let mut dc_only = true; // Horizontal pass: t[r][x] = Σ_u F[r][u] · B[u][x] - for r in 0..8 { - let c: &[f32; 8] = block[r * 8..r * 8 + 8].try_into().unwrap(); + for (r, c) in block.as_chunks::<8>().0.iter().enumerate() { if c[1..].iter().all(|&v| v == 0.0) { if c[0] != 0.0 { t[r] = [c[0] * BASIS[0][0]; 8]; diff --git a/crates/dnx/src/encode.rs b/crates/dnx/src/encode.rs index 4c5dbf58..914191f1 100644 --- a/crates/dnx/src/encode.rs +++ b/crates/dnx/src/encode.rs @@ -61,8 +61,9 @@ struct Prepared { } impl Encoder { - pub fn new(profile: Profile, width: u32, height: u32) -> Encoder { - Encoder::with_config(EncoderConfig::new(profile, width, height)).expect("valid default configuration") + /// An encoder with the default configuration; fails on rasters the profile can't code. + pub fn new(profile: Profile, width: u32, height: u32) -> Result { + Encoder::with_config(EncoderConfig::new(profile, width, height)) } pub fn with_config(cfg: EncoderConfig) -> Result { @@ -79,7 +80,7 @@ impl Encoder { if !ok_depth { return Err(Error::Input(format!("{} does not support {}-bit", cfg.profile.name(), cfg.bit_depth))); } - let info = cid_info(cfg.profile.cid()).expect("RI CID"); + let info = cid_info(cfg.profile.cid()).ok_or_else(|| Error::Input(format!("no compression table for {}", cfg.profile.name())))?; let frame_size = cfg.profile.frame_size(cfg.width, cfg.height); let header_size = header::header_size_for(cfg.height); Ok(Encoder { cfg, info, frame_size, header_size, last_q: 8 }) diff --git a/crates/dnx/src/header.rs b/crates/dnx/src/header.rs index 345fd173..24595380 100644 --- a/crates/dnx/src/header.rs +++ b/crates/dnx/src/header.rs @@ -152,7 +152,7 @@ pub fn parse(d: &[u8]) -> Result { 2 => ColorVolume::Bt2020Cl, _ => ColorVolume::OutOfBand, }; - let timecode = (d[0x30] & 0x80 != 0).then(|| d[0x31..0x39].try_into().unwrap()); + let timecode = if d[0x30] & 0x80 != 0 { d.get(0x31..).and_then(|t| t.first_chunk::<8>()).copied() } else { None }; let mb_rows = be16(d, 0x16C); if width == 0 || lines == 0 || width > 16384 || lines > 16384 { return Err(Error::Invalid("raster size")); diff --git a/crates/dnx/src/lib.rs b/crates/dnx/src/lib.rs index 87a3e0c4..a5f2b8c4 100644 --- a/crates/dnx/src/lib.rs +++ b/crates/dnx/src/lib.rs @@ -11,6 +11,8 @@ //! //! See the crate README for accuracy, performance and limitations. +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] + mod bits; mod dct; mod decode; diff --git a/crates/dnx/tests/roundtrip.rs b/crates/dnx/tests/roundtrip.rs index f677cd6e..41d39b4b 100644 --- a/crates/dnx/tests/roundtrip.rs +++ b/crates/dnx/tests/roundtrip.rs @@ -68,17 +68,20 @@ fn roundtrip_all_profiles() { #[test] fn rejects_bad_input() { - let mut enc = Encoder::new(Profile::Hq, 64, 64); + let mut enc = Encoder::new(Profile::Hq, 64, 64).unwrap(); assert!(enc.encode(&Frame::new(32, 64, ChromaFormat::Yuv422, 8, false)).is_err()); assert!(enc.encode(&Frame::new(64, 64, ChromaFormat::Yuv444, 8, false)).is_err()); assert!(Encoder::with_config(EncoderConfig { bit_depth: 10, ..EncoderConfig::new(Profile::Hq, 64, 64) }).is_err()); assert!(decode_frame(&[0u8; 100]).is_err()); assert!(decode_frame(&[0u8; 1000]).is_err()); + // An unsupported raster is an error, not a panic. + assert!(Encoder::new(Profile::Hq, 0, 0).is_err()); + assert!(Encoder::new(Profile::Hq, 20_000, 64).is_err()); } #[test] fn corrupt_streams_never_panic() { - let mut enc = Encoder::new(Profile::Hq, 256, 128); + let mut enc = Encoder::new(Profile::Hq, 256, 128).unwrap(); let good = enc.encode(&picture(256, 128, ChromaFormat::Yuv422, 8, 1)).unwrap(); let mut seed = 0x1234_5678u32; let mut rnd = || { diff --git a/crates/mpeg2v/src/bits.rs b/crates/mpeg2v/src/bits.rs index eb8f5040..2df38941 100644 --- a/crates/mpeg2v/src/bits.rs +++ b/crates/mpeg2v/src/bits.rs @@ -16,8 +16,8 @@ impl<'a> Bits<'a> { #[inline(always)] pub fn peek32(&self) -> u32 { let byte = self.pos >> 3; - let w = if byte + 8 <= self.data.len() { - u64::from_be_bytes(self.data[byte..byte + 8].try_into().expect("8 bytes")) + let w = if let Some(&b) = self.data.get(byte..).and_then(|d| d.first_chunk::<8>()) { + u64::from_be_bytes(b) } else { let mut b = [0u8; 8]; if byte < self.data.len() { diff --git a/crates/mpeg2v/src/lib.rs b/crates/mpeg2v/src/lib.rs index 7d3cc88f..261742c2 100644 --- a/crates/mpeg2v/src/lib.rs +++ b/crates/mpeg2v/src/lib.rs @@ -23,6 +23,8 @@ //! # Ok::<(), filmcraft_mpeg2v::Error>(()) //! ``` +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] + mod bits; pub mod headers; mod idct; diff --git a/crates/mpeg2v/src/vlc.rs b/crates/mpeg2v/src/vlc.rs index 438b9a2b..3ee5cd73 100644 --- a/crates/mpeg2v/src/vlc.rs +++ b/crates/mpeg2v/src/vlc.rs @@ -32,7 +32,8 @@ fn parse_code(s: &str) -> (u32, u32) { n += 1; } ' ' => {} - _ => panic!("bad code {s}"), + // Codes are literals in this crate; the table tests cover them. + _ => debug_assert!(false, "bad code {s}"), } } (v, n) diff --git a/crates/opus/src/celt/bands.rs b/crates/opus/src/celt/bands.rs index 1e413172..fbc1ab8f 100644 --- a/crates/opus/src/celt/bands.rs +++ b/crates/opus/src/celt/bands.rs @@ -783,8 +783,8 @@ pub fn quant_all_bands( } let out_off = xo - norm_offset; let x = &mut x_buf[xo..xo + n]; - if dual_stereo { - let y = &mut y_buf.as_deref_mut().expect("stereo")[xo..xo + n]; + if dual_stereo && let Some(y_buf) = y_buf.as_deref_mut() { + let y = &mut y_buf[xo..xo + n]; let lb = effective_lowband.map(|e| { scratch[..n].copy_from_slice(&norm[e..e + n]); &mut scratch[..n] diff --git a/crates/opus/src/lib.rs b/crates/opus/src/lib.rs index ca0e4941..ce28e481 100644 --- a/crates/opus/src/lib.rs +++ b/crates/opus/src/lib.rs @@ -2,6 +2,7 @@ //! //! Layer L0: no dependencies beyond `std`; no `unsafe`; builds for `wasm32-unknown-unknown`. +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] // The fixed-point parts mirror the normative integer arithmetic; keep C-like shift expressions. #![allow(clippy::precedence, clippy::int_plus_one)] diff --git a/crates/opus/src/silk/mod.rs b/crates/opus/src/silk/mod.rs index fd6c934a..b6c30735 100644 --- a/crates/opus/src/silk/mod.rs +++ b/crates/opus/src/silk/mod.rs @@ -211,8 +211,7 @@ impl Channel { (LostFlag::Lbrr, Some(_)) => self.lbrr_flags[self.n_frames_decoded], _ => false, }; - if decode { - let dec = dec.expect("range decoder"); + if decode && let Some(dec) = dec { self.decode_indices(dec, self.n_frames_decoded, lost == LostFlag::Lbrr, cond); let mut pulses = [0i32; MAX_FRAME + 16]; decode_pulses(dec, &mut pulses, self.indices.signal_type, self.indices.quant_offset_type, l); diff --git a/crates/prores/src/dct.rs b/crates/prores/src/dct.rs index f4ab8583..01faf661 100644 --- a/crates/prores/src/dct.rs +++ b/crates/prores/src/dct.rs @@ -19,8 +19,7 @@ pub(crate) fn idct8x8(block: &mut [f32; 64]) { let mut nz = [false; 8]; let mut dc_only = true; // Horizontal pass: t[r][x] = Σ_u F[r][u] · B[u][x] - for r in 0..8 { - let c: &[f32; 8] = block[r * 8..r * 8 + 8].try_into().unwrap(); + for (r, c) in block.as_chunks::<8>().0.iter().enumerate() { if c[1..].iter().all(|&v| v == 0.0) { if c[0] != 0.0 { t[r] = [c[0] * BASIS[0][0]; 8]; diff --git a/crates/prores/src/decode.rs b/crates/prores/src/decode.rs index 71dd1a87..d25c4935 100644 --- a/crates/prores/src/decode.rs +++ b/crates/prores/src/decode.rs @@ -476,8 +476,9 @@ fn put_block(f: &[f32; 64], plane: &mut [u16], stride: usize, x0: usize, y0: usi if xn == 8 && (y0 + 7) * step + parity < rows { for yy in 0..8 { let o = ((y0 + yy) * step + parity) * stride + x0; - let row: &mut [u16; 8] = (&mut plane[o..o + 8]).try_into().unwrap(); - let src: &[f32; 8] = f[yy * 8..yy * 8 + 8].try_into().unwrap(); + let (Some(row), Some(src)) = (plane.get_mut(o..).and_then(|p| p.first_chunk_mut::<8>()), f.as_chunks::<8>().0.get(yy)) else { + return; + }; for x in 0..8 { row[x] = conv.conv(src[x]); } diff --git a/crates/prores/src/encode.rs b/crates/prores/src/encode.rs index 6530d568..06d8cb65 100644 --- a/crates/prores/src/encode.rs +++ b/crates/prores/src/encode.rs @@ -429,7 +429,7 @@ fn write_slice(sd: &SliceData, q: u8) -> Vec { /// Encode the slice's alpha samples (16-bit coding) in raster order over its 16 lines. fn encode_alpha_slice(src: &Source, x0: usize, y0: usize, mbs: usize) -> Vec { - let a = src.frame.alpha.as_ref().expect("alpha checked"); + let Some(a) = src.frame.alpha.as_ref() else { return Vec::new() }; let d = src.frame.bit_depth as u32; let to16 = |v: u16| -> u32 { let v = v as u32 & ((1 << d) - 1); diff --git a/crates/prores/src/lib.rs b/crates/prores/src/lib.rs index 1e52fd97..fecc4274 100644 --- a/crates/prores/src/lib.rs +++ b/crates/prores/src/lib.rs @@ -9,6 +9,8 @@ //! //! See the crate README for bitstream details, accuracy and limitations. +#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))] + mod bits; mod dct; mod decode;