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/effects/src/lib.rs b/crates/effects/src/lib.rs index f3ada7d4..30d75a99 100644 --- a/crates/effects/src/lib.rs +++ b/crates/effects/src/lib.rs @@ -6,6 +6,8 @@ //! [`instantiate`]), so parameters animate, take expressions and are addressable like any other //! property. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] + pub mod audio_fx; mod blur2; mod blur3; @@ -551,8 +553,8 @@ pub fn instantiate(spec: &EffectSpec, ids: &mut Ids, instance_name: &str, layer_ if matches!(ps.ui, ParamUi::Checkbox | ParamUi::Popup { .. } | ParamUi::Layer) { pr.hold_only = true; } - match path { - Some(path) => nested_group(&mut g, ids, path).children.push(pr.into()), + match path.and_then(|path| nested_group(&mut g, ids, path)) { + Some(sub) => sub.children.push(pr.into()), None => g.children.push(pr.into()), } // Layer parameters carry a source choice (Source / Masks / Effects & Masks) unless the @@ -563,8 +565,8 @@ pub fn instantiate(spec: &EffectSpec, ids: &mut Ids, instance_name: &str, layer_ if matches!(ps.ui, ParamUi::Layer) && !spec.params.iter().any(|q| q.id == sid) { let mut src = Property::new(ids.alloc(), &layer_source_id(leaf), &format!("{} Source", ps.name), Value::Enum(2)).with_ui(ParamUi::Hidden); src.hold_only = true; - match path { - Some(path) => nested_group(&mut g, ids, path).children.push(src.into()), + match path.and_then(|path| nested_group(&mut g, ids, path)) { + Some(sub) => sub.children.push(src.into()), None => g.children.push(src.into()), } } @@ -765,7 +767,7 @@ fn group_name(m: &str) -> &str { } /// The nested group at `path` (`borders/autoScale`) under `g`, created on first use. -fn nested_group<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> &'a mut PropGroup { +fn nested_group<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> Option<&'a mut PropGroup> { let (first, rest) = match path.split_once('/') { Some((a, b)) => (a, Some(b)), None => (path, None), @@ -773,10 +775,10 @@ fn nested_group<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> &'a mut if g.sub(first).is_none() { g.children.push(ids.group(first, group_name(first)).into()); } - let sub = g.sub_mut(first).expect("just added"); + let sub = g.sub_mut(first)?; match rest { Some(r) => nested_group(sub, ids, r), - None => sub, + None => Some(sub), } } diff --git a/crates/effects/src/migrate.rs b/crates/effects/src/migrate.rs index e5dc30ba..44d14260 100644 --- a/crates/effects/src/migrate.rs +++ b/crates/effects/src/migrate.rs @@ -192,7 +192,7 @@ fn prop_at<'a>(g: &'a mut PropGroup, id: &str) -> Option<&'a mut Property> { } } -fn group_at<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> &'a mut PropGroup { +fn group_at<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> Option<&'a mut PropGroup> { let (first, rest) = match path.split_once('/') { Some((a, b)) => (a, Some(b)), None => (path, None), @@ -200,10 +200,10 @@ fn group_at<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> &'a mut Prop if g.sub(first).is_none() { g.children.push(ids.group(first, group_name(first)).into()); } - let sub = g.sub_mut(first).expect("just added"); + let sub = g.sub_mut(first)?; match rest { Some(r) => group_at(sub, ids, r), - None => sub, + None => Some(sub), } } @@ -288,8 +288,8 @@ pub fn upgrade_instance(spec: &EffectSpec, g: &mut PropGroup, ids: &mut Ids, lay pr } }; - match path { - Some(path) => group_at(g, ids, path).children.push(pr.into()), + match path.and_then(|path| group_at(g, ids, path)) { + Some(sub) => sub.children.push(pr.into()), None => g.children.push(pr.into()), } } @@ -310,8 +310,8 @@ pub fn upgrade_instance(spec: &EffectSpec, g: &mut PropGroup, ids: &mut Ids, lay src.hold_only = true; src }); - match path { - Some(path) => group_at(g, ids, path).children.push(src.into()), + match path.and_then(|path| group_at(g, ids, path)) { + Some(sub) => sub.children.push(src.into()), None => g.children.push(src.into()), } } @@ -363,7 +363,7 @@ mod tests { let removed = spec.params.last().unwrap().id; g.children.retain(|c| c.match_id() != removed); let popup = spec.params.iter().find(|p| matches!(p.ui, ParamUi::Popup { .. })).expect("Gaussian Blur has a popup"); - let ParamUi::Popup { options } = &popup.ui else { unreachable!() }; + let ParamUi::Popup { options } = &popup.ui else { panic!("not a popup") }; { let pr = g.get_mut(popup.id).unwrap(); pr.name = "Old Name".into(); diff --git a/crates/effects/src/ocio.rs b/crates/effects/src/ocio.rs index de0952b1..c11c20cd 100644 --- a/crates/effects/src/ocio.rs +++ b/crates/effects/src/ocio.rs @@ -128,10 +128,14 @@ const fn sp(name: &'static str, prims: [[f64; 2]; 3], white: [f64; 2], tf: Tf) - } /// The built-in configuration's colour spaces, in popup order. +const ACES2065_1: Space = sp("ACES2065-1", AP0, ACES_WHITE, Tf::Linear); +const ACES_CG: Space = sp("ACEScg", AP1, ACES_WHITE, Tf::Linear); +const ACES_CCT: Space = sp("ACEScct", AP1, ACES_WHITE, Tf::AcesCct); + pub const SPACES: &[Space] = &[ - sp("ACES2065-1", AP0, ACES_WHITE, Tf::Linear), - sp("ACEScg", AP1, ACES_WHITE, Tf::Linear), - sp("ACEScct", AP1, ACES_WHITE, Tf::AcesCct), + ACES2065_1, + ACES_CG, + ACES_CCT, sp("Linear Rec.709 (sRGB)", REC709, D65, Tf::Linear), sp("sRGB", REC709, D65, Tf::Srgb), sp("Gamma 2.4 Rec.709", REC709, D65, Tf::Gamma(2.4)), @@ -147,6 +151,7 @@ pub fn space_names() -> Vec<&'static str> { SPACES.iter().map(|s| s.name).collect() } +#[cfg(test)] pub fn space_by_name(n: &str) -> Option<&'static Space> { SPACES.iter().find(|s| s.name.eq_ignore_ascii_case(n)) } @@ -778,7 +783,7 @@ fn ocio_look(ctx: &EffectCtx, mut b: Buf) -> Buf { } let (src, dst) = (space_at(ctx.params.e("source")), space_at(ctx.params.e("destination"))); let inv = ctx.params.e("direction") == 1; - let cct = space_by_name("ACEScct").expect("built-in"); + let cct = &ACES_CCT; let (a, z) = if inv { (dst, src) } else { (src, dst) }; let to_p = Xform::new(a, cct); let from_p = Xform::new(cct, z); @@ -805,8 +810,8 @@ fn profile(ctx: &EffectCtx, i: u32) -> (Space, bool) { ColorSpace::Rec709 => sp("Rec.709", REC709, D65, Tf::Gamma(2.4)), ColorSpace::Rec2020 => sp("Rec.2020", REC2020, D65, Tf::Gamma(2.4)), ColorSpace::DisplayP3 => sp("Display P3", P3, D65, Tf::Srgb), - ColorSpace::AcesCg => *space_by_name("ACEScg").expect("built-in"), - ColorSpace::Aces2065 => *space_by_name("ACES2065-1").expect("built-in"), + ColorSpace::AcesCg => ACES_CG, + ColorSpace::Aces2065 => ACES2065_1, // HDR encodings are output spaces, never a working space. ColorSpace::Rec2100Pq | ColorSpace::Rec2100Hlg => sp("Rec.2020", REC2020, D65, Tf::Gamma(2.4)), }; @@ -816,8 +821,8 @@ fn profile(ctx: &EffectCtx, i: u32) -> (Space, bool) { 2 => (ws(ColorSpace::Rec709), false), 3 => (ws(ColorSpace::Rec2020), false), 4 => (ws(ColorSpace::DisplayP3), false), - 5 => (*space_by_name("ACEScg").expect("built-in"), true), - _ => (*space_by_name("ACES2065-1").expect("built-in"), true), + 5 => (ACES_CG, true), + _ => (ACES2065_1, true), } } @@ -1089,7 +1094,7 @@ pub fn color_program(id: &str, ctx: &EffectCtx) -> Option<(Vec, Straigh if !list.is_empty() { let (src, dst) = (space_at(pr.e("source")), space_at(pr.e("destination"))); let inv = pr.e("direction") == 1; - let cct = space_by_name("ACEScct").expect("built-in"); + let cct = &ACES_CCT; let (a, z) = if inv { (dst, src) } else { (src, dst) }; if inv { list.reverse(); @@ -1157,7 +1162,7 @@ fn curve3(xs: [f64; 3], ys: [f64; 3], v: f64) -> f64 { let mut pairs: Vec<(f64, f64)> = xs.iter().cloned().zip(ys.iter().cloned()).collect(); pairs.sort_by(|a, b| a.0.total_cmp(&b.0)); for (x, y) in pairs { - if x > pts.last().expect("non-empty").0 + 1e-4 && x < 1.0 - 1e-4 { + if pts.last().is_some_and(|l| x > l.0 + 1e-4) && x < 1.0 - 1e-4 { pts.push((x, y)); } } @@ -1196,7 +1201,7 @@ pub fn color_stabilizer_maps(ctx: &EffectCtx, b: &Buf) -> Option<[Vec<(f64, f64) let mut pairs: Vec<(f64, f64)> = (0..3).map(|i| (cur[i][k], refv[i][k])).collect(); pairs.sort_by(|a, b| a.0.total_cmp(&b.0)); for (x, y) in pairs { - if x > v.last().expect("non-empty").0 + 1e-4 && x < 1.0 - 1e-4 { + if v.last().is_some_and(|l| x > l.0 + 1e-4) && x < 1.0 - 1e-4 { v.push((x, y)); } } diff --git a/crates/effects/src/textfx.rs b/crates/effects/src/textfx.rs index 76d71806..34282c27 100644 --- a/crates/effects/src/textfx.rs +++ b/crates/effects/src/textfx.rs @@ -686,13 +686,10 @@ fn path_text_passes(ctx: &EffectCtx, b: &Buf) -> Vec { let js = if j_scale != 0.0 { (1.0 + rnd(i, 4) * j_scale).max(0.05) } else { 1.0 }; let jb = if j_base != 0.0 { rnd(i, 1) * j_base } else { 0.0 }; let left = ink_left(c, true); - let set = match polys_by_alpha.iter_mut().find(|(a, _)| (*a - alpha).abs() < 1e-4) { - Some((_, v)) => v, - None => { - polys_by_alpha.push((alpha, Vec::new())); - &mut polys_by_alpha.last_mut().expect("pushed").1 - } - }; + if !polys_by_alpha.iter().any(|(a, _)| (*a - alpha).abs() < 1e-4) { + polys_by_alpha.push((alpha, Vec::new())); + } + let Some((_, set)) = polys_by_alpha.iter_mut().find(|(a, _)| (*a - alpha).abs() < 1e-4) else { continue }; for st in parse_glyph(c) { set.push( st.iter()