1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! Per-metric implementations.
//!
//! Each submodule defines one maintainability metric, its per-language
//! traits, and its `Stats` accumulator. See the crate-level docs for an
//! overview of the metric suite.
/// Assignment / Branch / Condition counts.
/// Cognitive complexity.
/// Cyclomatic complexity.
/// Halstead suite (operators, operands, volume, difficulty, effort).
/// Lines-of-code variants (SLOC, PLOC, LLOC, CLOC, blank).
/// Maintainability Index.
/// Number of arguments per function.
/// Exit-point counting.
/// Number of methods (functions + closures).
/// Number of public attributes.
/// Number of public methods.
/// Token count.
/// Weighted Methods per Class.
/// Divides a metric sum by a count, guarding the divisor with `.max(1)`.
///
/// Every "average over a count" metric routes through this helper so the
/// divide-by-zero guard added for [#428] is applied uniformly rather than
/// per call site. A `count` of `0` degrades to `sum / 1` (the sum itself)
/// instead of producing `inf`/`NaN`, so a never-observed or count-less
/// space still serializes a finite number.
///
/// The *meaning* of `count` is the caller's choice of denominator
/// convention; the project uses two:
///
/// - **Per-function** averages (`cognitive`, `cyclomatic`, `exit`,
/// `nargs`) divide by the function/closure count of the subtree, so the
/// value reads as "average complexity per function". `cognitive`/
/// `exit`/`nargs` source this count from `Nom`; `cyclomatic` counts its
/// own function/closure *spaces* (equal in the common case, but
/// independent of whether `Nom` is selected — see
/// `cyclomatic::Stats::function_spaces`).
/// - **Per-space** averages (`nom`, `loc`, `abc`, `tokens`) divide by the
/// total number of spaces (functions, closures, classes, the file unit,
/// …). These measure a property of each space rather than of each
/// function, so a per-function denominator would not match their
/// meaning (and for `nom` it would be circular — it *is* the function
/// count).
///
/// [#428]: https://github.com/dekobon/big-code-analysis/issues/428
// `count as f64` is exact for any realistic space count; the cast mirrors
// the per-metric modules' module-level allowance for count-to-float casts.
pub