cccc-rs 0.2.0

Rust (syn) adapter that lowers source into the cccc-core complexity IR
Documentation
  • Coverage
  • 100%
    4 out of 4 items documented0 out of 2 items with examples
  • Size
  • Source code size: 22.43 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 372.64 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 7s Average build duration of successful builds.
  • all releases: 7s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • moznion/cccc
    7 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • moznion

Rust adapter: parses source with syn and lowers the AST into the language-agnostic [cccc_core::ir].

This is a pure library — it depends only on cccc-core and syn, with no CLI machinery, so embedders pay nothing for clap/ignore/rayon. The cccc-rs binary lives in the separate cccc-rs-cli crate, which combines [analyze_source]/[DEFAULT_EXTS] with the shared cccc-cli runner.

This crate contains no scoring logic — it only recognizes the constructs the engine cares about (functions/methods/closures, if/else, match, loops, labelled jumps, &&/|| sequences, calls) and emits the matching IR nodes. All complexity rules live in [cccc_core::engine].

Why a Visit-driven builder

Lowering is driven by syn's [Visit] trait. Its default visit_* methods traverse the entire AST; we override only the nodes that produce IR, so a nested function or logical operator appearing in any expression position is still reached — we never have to enumerate every node kind by hand. The IR tree is assembled with a stack of "collectors": [Builder::collect] pushes a fresh child vector, runs a sub-traversal, and pops the nodes it gathered.

Rust-to-IR mapping notes

  • fn / impl method / trait default method / closure → [Node::Function].
  • if / else if / else → [Node::Branch] (chaining else if as a nested Branch so it scores flat). if let / while let are just the same nodes.
  • for / while / loop → [Node::Loop].
  • match → [Node::Switch]; a _ (or bare binding) arm is the default. An arm guard (pat if cond) is visited inside the case body.
  • labelled break 'a / continue 'a → [Node::Jump] (labeled: true).
  • && / || runs → folded [Node::Logical] (one node per like-operator run).
  • calls (f(..), obj.m(..)) → [Node::Call] for recursion detection.

Rust has no ternary (if is an expression instead) and no try/catch (errors propagate via ?), so no Conditional/Catch nodes are emitted.