Skip to content

Contributing

Contributions to RustQC are welcome. This page covers how to build, test, and submit changes.

git clone https://github.com/ewels/RustQC.git
cd RustQC
# Debug build
cargo build
# Release build (optimized, used for benchmarking)
cargo build --release

See the Installation page for system dependency requirements (cmake, zlib, bz2, lzma, curl, ssl, clang).

# Run all tests (unit + integration)
cargo test
# Run in release mode (matches CI)
cargo test --release
# Run only unit tests
cargo test --lib
# Run only integration tests
cargo test --test integration_test
# Run a specific test by name
cargo test test_dup_rate_calculation

Integration tests in tests/integration_test.rs run the compiled binary as a subprocess and compare output against R-generated reference files in tests/expected/. Do not modify files in tests/expected/ by hand — they are generated by tests/create_test_data.R.

Both checks are enforced in CI and must pass before merging:

# Auto-format code
cargo fmt
# Check formatting without modifying files
cargo fmt --check
# Run clippy (all warnings are errors)
cargo clippy -- -D warnings

RustQC uses default rustfmt settings (no rustfmt.toml) and default clippy settings with -D warnings.

RustQC is a binary crate with a nested module structure. Top-level modules are declared in main.rs with no lib.rs.

src/
main.rs Entry point, dispatches subcommands
cli.rs CLI argument parsing (clap derive)
config.rs YAML configuration loading (serde)
io.rs Shared I/O utilities (gzip-transparent file reading)
gtf.rs GTF annotation file parser
rna/
mod.rs Re-exports dupradar, featurecounts, rseqc
dupradar/
mod.rs Re-exports counting, dupmatrix, fitting, plots
counting.rs BAM read counting engine
dupmatrix.rs Duplication matrix construction and TSV output
fitting.rs Logistic regression via IRLS
plots.rs Plot generation (density scatter, boxplot, histogram)
featurecounts/
mod.rs Re-exports output
output.rs featureCounts-format output and biotype counting
rseqc/
mod.rs Re-exports all RSeQC modules
bam_stat.rs BAM alignment statistics (bam_stat.py)
infer_experiment.rs Library strandedness inference (infer_experiment.py)
read_duplication.rs Duplication rate histograms (read_duplication.py)
read_distribution.rs Read distribution across features (read_distribution.py)
junction_annotation.rs Splice junction classification (junction_annotation.py)
junction_saturation.rs Junction saturation analysis (junction_saturation.py)
inner_distance.rs Paired-end inner distance (inner_distance.py)
tests/
integration_test.rs Integration tests vs R reference output
data/ Test BAM/GTF input files
expected/ R-generated reference outputs
create_test_data.R R script to regenerate test data

Inter-module access uses crate:: paths (e.g., use crate::rna::dupradar::counting::count_reads;).

Key conventions:

  • Formatting: Default rustfmt, 4-space indentation, trailing commas on multi-line constructs.
  • Error handling: anyhow::Result<T> for all fallible functions. Propagate with ?, add context with .context(). No custom error types.
  • Documentation: Every source file starts with //! module doc comments. All public items have /// doc comments.
  • Naming: Types are CamelCase, functions/variables are snake_case, constants are SCREAMING_SNAKE_CASE.
  • Types: u64 for counts/positions, f64 for metrics, u8 for flags. IndexMap when insertion order matters, HashMap otherwise.
  • Tests: Unit tests are co-located in each source file inside #[cfg(test)] mod tests. Test names follow test_<description>.
  • unwrap() / expect(): Restricted to test code only. In production code, use ? with anyhow context.

GitHub Actions runs on push to main and all pull requests:

  1. Testcargo test --release on Ubuntu and macOS
  2. Formatcargo fmt --check
  3. Clippycargo clippy -- -D warnings

All three checks must pass. The CI uses dtolnay/rust-toolchain@stable and Swatinem/rust-cache@v2.

  1. Fork the repository and create a feature branch.
  2. Make your changes, ensuring cargo test, cargo fmt --check, and cargo clippy -- -D warnings all pass locally.
  3. Open a pull request against main with a clear description of the changes.