Skip to main content

dry4rust/cli/checking/
check_thresholds.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::error::Result;
7use crate::threshold::Threshold;
8
9/// The four ceilings `check` measures a result against.
10///
11/// Every field is optional and an absent one is not a ceiling of zero -- it
12/// means the caller did not ask about that dimension, so nothing can breach
13/// it. `Default` therefore describes a `check` that reports and never fails,
14/// which is what running `check` with no flags does.
15#[derive(Debug, Clone, Default)]
16pub struct CheckThresholds {
17    /// Most exact-duplicate groups allowed.
18    pub max_exact: Option<usize>,
19    /// Most near-duplicate groups allowed.
20    pub max_near: Option<usize>,
21    /// Largest share of lines allowed to be exact duplicates.
22    pub max_exact_percent: Option<Threshold>,
23    /// Largest share of lines allowed to be near duplicates.
24    pub max_near_percent: Option<Threshold>,
25}
26
27impl CheckThresholds {
28    /// Build the ceilings from what the command line asked for.
29    ///
30    /// # Errors
31    ///
32    /// Returns [`crate::error::Error::InvalidConfig`] naming the flag whose
33    /// value is not a share of a hundred.
34    pub fn new(
35        max_exact: Option<usize>,
36        max_near: Option<usize>,
37        max_exact_percent: Option<f64>,
38        max_near_percent: Option<f64>,
39    ) -> Result<Self> {
40        Ok(Self {
41            max_exact,
42            max_near,
43            max_exact_percent: max_exact_percent
44                .map(|value| Threshold::percent("--max-exact-percent", value))
45                .transpose()?,
46            max_near_percent: max_near_percent
47                .map(|value| Threshold::percent("--max-near-percent", value))
48                .transpose()?,
49        })
50    }
51
52    /// Whether any ceiling was set at all.
53    ///
54    /// A `check` with none set can still report, and still exits zero however
55    /// much duplication it finds.
56    #[must_use]
57    pub const fn is_unbounded(&self) -> bool {
58        self.max_exact.is_none()
59            && self.max_near.is_none()
60            && self.max_exact_percent.is_none()
61            && self.max_near_percent.is_none()
62    }
63}