Skip to main content

dry4rust/suppression/
baseline_filter.rs

1// Copyright (c) 2026 Matjaz Domen Pecan
2// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
3// Licensed under the MIT License
4// SPDX-License-Identifier: MIT
5
6use crate::config::Config;
7use crate::error::Result;
8use crate::grouper::DuplicateGroup;
9use crate::suppression::baseline_file::BaselineFile;
10use crate::suppression::baseline_file::baseline_path;
11use crate::suppression::baseline_kind::BaselineKind;
12
13/// Keeps the duplication a baseline did not already account for.
14///
15/// With no baseline configured this is the identity, and `is_in_effect` says
16/// so -- which is what lets the summary report a suppressed count only when
17/// there is something doing the suppressing.
18pub struct BaselineFilter {
19    recorded: Option<BaselineFile>,
20}
21
22impl BaselineFilter {
23    /// Read the baseline `config` names, if it names one.
24    ///
25    /// # Errors
26    ///
27    /// Returns [`crate::error::Error::Baseline`] when a baseline is named and
28    /// cannot be read.
29    pub fn load(config: &Config) -> Result<Self> {
30        let Some(configured) = config.baseline.as_deref() else {
31            return Ok(Self { recorded: None });
32        };
33        let path = baseline_path(&config.root, Some(configured));
34        Ok(Self {
35            recorded: Some(BaselineFile::load(&path)?),
36        })
37    }
38
39    /// A filter that suppresses nothing, for a run recording a baseline rather
40    /// than judging against one.
41    #[must_use]
42    pub const fn none() -> Self {
43        Self { recorded: None }
44    }
45
46    /// Whether a baseline was loaded at all.
47    #[must_use]
48    pub const fn is_in_effect(&self) -> bool {
49        self.recorded.is_some()
50    }
51
52    /// Drop the groups the baseline already accounts for.
53    #[must_use]
54    pub fn retain_new(
55        &self,
56        kind: BaselineKind,
57        groups: Vec<DuplicateGroup>,
58    ) -> Vec<DuplicateGroup> {
59        let Some(recorded) = self.recorded.as_ref() else {
60            return groups;
61        };
62        groups
63            .into_iter()
64            .filter(|group| !recorded.admits(kind, group))
65            .collect()
66    }
67}