A minimalist, AST-driven Rust lines of code counter with intelligent production/test separation.
ruloc provides precise source code metrics for Rust projects by leveraging AST-based parsing to accurately distinguish between production and test code. It counts blank lines, comments, rustdoc documentation, and executable code—all while maintaining a simple, single-file architecture that's easy to understand and extend.
- AST-driven accuracy — Uses
ra_ap_syntax
for token-level parsing, correctly handling comments in strings, raw strings, and complex macros. - Smart test detection — Automatically identifies
#[test]
functions and#[cfg(test)]
modules, providing separate metrics for production and test code. - Rustdoc-aware — Distinguishes documentation comments (
///
,//!
,/**
,/*!
) from regular comments. - Memory-efficient — File-backed accumulator supports analyzing arbitrarily large codebases without exhausting RAM.
- Parallel processing — Leverages Rayon for concurrent file analysis on multi-core systems.
- Debug mode — Line-by-line output with color-coded type markers (PBL, PCO, PCM, PDC, TBL, TCO, TCM, TDC) for detailed inspection.
- Single file — Entire implementation in
src/main.rs
. No hidden complexity.
Analyze your Rust project in seconds:
# Install from source
cargo install --path .
# Analyze a single file
ruloc --file src/main.rs
# Analyze an entire directory
ruloc --dir src/
# JSON output for CI/CD integration
ruloc --dir . --out-json
Clone the repository and install locally:
git clone https://github.com/nutthead/ruloc.git
cd ruloc
cargo install --path .
If you have Rust installed:
cargo install ruloc
(Note: Package not yet published to crates.io)
Analyze a single Rust source file:
ruloc --file src/main.rs
Analyze all Rust files in a directory recursively:
ruloc --dir src/
Plain text output (default):
ruloc --dir src/
JSON output for programmatic consumption:
ruloc --dir src/ --out-json
Limit maximum file size to skip large generated files:
ruloc --dir src/ --max-file-size 1MB
# Supports: bytes (default), KB, MB, GB
# Examples: 1000, 3.5KB, 10MB, 1.1GB
Enable verbose logging for debugging:
ruloc --dir src/ --verbose
Inspect exactly how ruloc classifies each line with debug mode:
ruloc --file src/main.rs --debug
Output shows color-coded prefixes for each line:
src/main.rs:
PDC /// Production rustdoc comment
PCO fn production() {}
PBL
PCM // Production comment
TBL
TCO #[cfg(test)]
TCO mod tests {
TDC /// Test rustdoc comment
TCO #[test]
TCO fn test_one() {
TCM // Test comment
TCO }
TCO }
Debug marker legend:
- PBL — Production BLank line
- PCO — Production COde line
- PCM — Production CoMment line
- PDC — Production DoC (rustdoc) line
- TBL — Test BLank line
- TCO — Test COde line
- TCM — Test CoMment line
- TDC — Test DoC (rustdoc) line
Disable colors in debug mode:
ruloc --file src/main.rs --debug --no-color
$ ruloc --file src/main.rs
Summary:
Files: 1
Total:
All lines: 3838
Blank lines: 519
Comment lines: 141
Rustdoc lines: 767
Code lines: 2411
Production:
All lines: 1537
Blank lines: 159
Comment lines: 44
Rustdoc lines: 586
Code lines: 748
Test:
All lines: 2301
Blank lines: 360
Comment lines: 97
Rustdoc lines: 181
Code lines: 1663
$ ruloc --file src/main.rs --out-json
{
"summary": {
"files": 1,
"total": {
"all-lines": 3838,
"blank-lines": 519,
"comment-lines": 141,
"rustdoc-lines": 767,
"code-lines": 2411
},
"production": {
"all-lines": 1537,
"blank-lines": 159,
"comment-lines": 44,
"rustdoc-lines": 586,
"code-lines": 748
},
"test": {
"all-lines": 2301,
"blank-lines": 360,
"comment-lines": 97,
"rustdoc-lines": 181,
"code-lines": 1663
}
},
"files": [
{
"path": "src/main.rs",
"total": {
"all-lines": 3838,
"blank-lines": 519,
"comment-lines": 141,
"rustdoc-lines": 767,
"code-lines": 2411
},
"production": {
"all-lines": 1537,
"blank-lines": 159,
"comment-lines": 44,
"rustdoc-lines": 586,
"code-lines": 748
},
"test": {
"all-lines": 2301,
"blank-lines": 360,
"comment-lines": 97,
"rustdoc-lines": 181,
"code-lines": 1663
}
}
]
}
ruloc was built to provide accurate, production-grade metrics for Rust codebases while maintaining architectural simplicity:
- Single-file implementation — All functionality resides in
src/main.rs
(~3600 lines including comprehensive tests and rustdoc), making the codebase transparent and easy to audit. - AST-based classification — Uses the same parser as rust-analyzer (
ra_ap_syntax
) to tokenize source code, ensuring accurate classification even in complex scenarios like comments within raw strings or macro invocations. - Two-pass analysis — First pass classifies each line as blank, comment, rustdoc, or code. Second pass traverses the AST to identify test sections marked with
#[test]
or#[cfg(test)]
attributes. - Scalable architecture — Implements both in-memory and file-backed accumulators, enabling analysis of projects with millions of lines without memory constraints.
- Parallel processing — Uses Rayon to analyze files concurrently, maximizing throughput on multi-core systems.
ruloc employs a dual-analysis strategy:
-
Token-level line classification:
- Parses source into a syntax tree using
ra_ap_syntax
- Maps each token to its containing line(s)
- Classifies lines based on token types (whitespace, comment, rustdoc, code)
- Handles edge cases: comments in strings, multi-line constructs, raw strings
- Parses source into a syntax tree using
-
AST-based test detection:
- Recursively traverses the syntax tree
- Identifies functions with
#[test]
attributes - Identifies modules/functions with
#[cfg(test)]
attributes - Verifies
cfg(test)
specifically (notcfg(unix)
, etc.) by inspecting token trees - Marks all lines within identified sections as test code
This approach combines the precision of AST parsing with the simplicity of line-based metrics, providing accurate results while remaining conceptually straightforward.
- Rust 1.70+ (uses
let-else
statements) - Standard Rust toolchain (
rustc
,cargo
)
# Type checking (fast feedback)
cargo check
# Format code
cargo fmt
# Lint with Clippy
cargo clippy --all-targets --all-features -- -D warnings
# Run tests
cargo test
# Build optimized binary
cargo build --release
# Run against a target
cargo run -- --dir src/
ruloc maintains ≥70% code coverage using tarpaulin:
# Install tarpaulin (requires OpenSSL development libraries)
cargo install cargo-tarpaulin
# Run coverage analysis
cargo tarpaulin
# Coverage configuration in .tarpaulin.toml
# Reports: HTML (target/tarpaulin/index.html), XML, JSON, LCOV
ruloc/
├── src/
│ └── main.rs # Complete implementation (~3600 lines)
├── Cargo.toml # Dependencies and metadata
├── .tarpaulin.toml # Coverage configuration (≥70% threshold)
├── CLAUDE.md # Development guidelines for AI assistants
└── README.md # This file
- Format and lint — Ensure
cargo fmt
andcargo clippy
pass - Test coverage — Add tests for new functionality; maintain ≥70% coverage
- Documentation — Update rustdoc comments to match code changes
- Commit style — Follow Conventional Commits (
feat:
,fix:
,refactor:
, etc.)
Issues and pull requests are welcome. Before submitting:
- Run
cargo fmt
andcargo clippy --all-targets --all-features -- -D warnings
- Ensure
cargo test
passes with all tests succeeding - Verify
cargo tarpaulin
reports ≥70% coverage - Update rustdoc comments for any modified APIs
- Follow Conventional Commit message format