Skip to main content

braintax/
lib.rs

1//! # braintax
2//!
3//! A minimal utility crate for estimating the cognitive "tax" of code patterns.
4//!
5//! This crate provides a simple scoring function that quantifies how mentally
6//! taxing a given code structure is, based on nesting depth and branching
7//! complexity. It is designed as a lightweight companion to complexity analysis
8//! tools like `crap4rust`.
9//!
10//! ## Example
11//!
12//! ```rust
13//! use braintax::Braintax;
14//!
15//! let score = Braintax::new()
16//!     .with_nesting(3)
17//!     .with_branches(5)
18//!     .compute();
19//!
20//! assert!(score > 0);
21//! ```
22
23/// A cognitive "tax" estimator that combines nesting depth and branching
24/// complexity into a single score.
25///
26/// The formula is intentionally simple:
27/// `tax = nesting² + branches + 1`
28///
29/// This provides a rough heuristic: deeply nested code with many branches
30/// is more mentally taxing to read and maintain.
31#[derive(Clone, Copy, Debug, Default)]
32pub struct Braintax {
33    nesting: u32,
34    branches: u32,
35}
36
37impl Braintax {
38    /// Creates a new `Braintax` with zero nesting and zero branches.
39    #[must_use]
40    pub fn new() -> Self {
41        Self::default()
42    }
43
44    /// Sets the nesting depth (e.g., how many levels deep control flow is nested).
45    #[must_use]
46    pub const fn with_nesting(mut self, nesting: u32) -> Self {
47        self.nesting = nesting;
48        self
49    }
50
51    /// Sets the number of branching points (e.g., `if`, `match`, `loop` constructs).
52    #[must_use]
53    pub const fn with_branches(mut self, branches: u32) -> Self {
54        self.branches = branches;
55        self
56    }
57
58    /// Computes the cognitive tax score.
59    ///
60    /// # Formula
61    ///
62    /// ```text
63    /// tax = nesting² + branches + 1
64    /// ```
65    ///
66    /// A score of **1** represents the baseline (no nesting, no branches).
67    /// Higher scores indicate increasing mental taxation.
68    #[must_use]
69    pub const fn compute(&self) -> u64 {
70        (self.nesting as u64).pow(2) + self.branches as u64 + 1
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn baseline_returns_one() {
80        let tax = Braintax::new().compute();
81        assert_eq!(tax, 1);
82    }
83
84    #[test]
85    fn nesting_increases_score_quadratically() {
86        let tax = Braintax::new().with_nesting(3).compute();
87        assert_eq!(tax, 10); // 3² + 0 + 1 = 10
88    }
89
90    #[test]
91    fn branches_add_linearly() {
92        let tax = Braintax::new().with_branches(5).compute();
93        assert_eq!(tax, 6); // 0² + 5 + 1 = 6
94    }
95
96    #[test]
97    fn combined_nesting_and_branches() {
98        let tax = Braintax::new().with_nesting(2).with_branches(4).compute();
99        assert_eq!(tax, 9); // 2² + 4 + 1 = 9
100    }
101
102    #[test]
103    fn large_values_do_not_overflow() {
104        let tax = Braintax::new()
105            .with_nesting(1_000)
106            .with_branches(100_000)
107            .compute();
108        assert_eq!(tax, 1_100_001); // 1000² + 100000 + 1 = 1_100_001
109    }
110
111    #[test]
112    fn debug_format_does_not_panic() {
113        let tax = Braintax::new().with_nesting(1).with_branches(2);
114        let _ = format!("{tax:?}");
115    }
116
117    #[test]
118    fn clone_produces_equal_score() {
119        let original = Braintax::new().with_nesting(4).with_branches(3);
120        let cloned = original;
121        assert_eq!(original.compute(), cloned.compute());
122    }
123}