Thank you for your interest in contributing to TP-Lib! This document provides guidelines and instructions for contributing.
Be respectful and professional in all interactions. We're all here to build better software together.
- Rust: 1.91.1 or later (Install rustup)
- Python: 3.12 or later (for Python bindings)
- Git: For version control
- Docker: Optional, for containerized testing
# Clone the repository
git clone https://github.com/matdata-eu/tp-lib.git
cd tp-lib
# Build all workspace crates
cargo build --workspace
# Run tests
cargo test --workspace --all-features
# Build Python bindings
cd tp-py
pip install maturin pytest
maturin develop
pytest python/tests/TP-Lib follows Test-Driven Development (TDD):
- RED: Write a failing test first
- GREEN: Write minimum code to make it pass
- REFACTOR: Improve code while keeping tests green
Run these checks locally:
# Format code
cargo fmt --all
# Check formatting
cargo fmt --all --check
# Run linter
cargo clippy --workspace --all-targets --all-features -- -D warnings
# Run security/license check
cargo deny check
# Run all tests
cargo test --workspace --all-features
# Test Python bindings
cd tp-py
maturin develop
pytestUse Conventional Commits:
feat: add new CRS transformation
fix: correct haversine distance calculation
docs: update API documentation
test: add integration tests for projection
chore: update dependencies
refactor: simplify spatial indexing
- Fork the repository
- Create a branch from
main:git checkout -b feature/your-feature-name
- Make changes following TDD workflow
- Run all checks (see "Before Committing")
- Push to your fork
- Open a Pull Request against
main
Your PR must:
- ✅ Pass all CI checks (tests, linting, security)
- ✅ Include tests for new functionality
- ✅ Update documentation if needed
- ✅ Follow code style (enforced by rustfmt)
- ✅ Have clear commit messages
- ✅ Not introduce security vulnerabilities
CI Checks:
- Test Suite (Rust tests)
- Python Tests
- Linting (rustfmt + clippy)
- License & Security Check (cargo-deny)
See docs/WORKFLOWS.md for details on CI/CD automation.
-
Unit Tests: Test individual functions/methods
#[cfg(test)] mod tests { use super::*; #[test] fn test_haversine_distance() { // Arrange let pos1 = Point::new(50.0, 4.0); let pos2 = Point::new(50.1, 4.1); // Act let distance = haversine_distance(&pos1, &pos2); // Assert assert!((distance - 13545.0).abs() < 1.0); } }
-
Integration Tests: Test component interactions
- Located in
tests/directory - Test complete workflows
- Located in
-
Contract Tests: Verify CLI behavior
- Located in
tests/contract/ - Test exit codes, output formats
- Located in
-
Doc Tests: Examples in documentation
/// Calculate distance between two points /// /// ``` /// use tp_lib_core::haversine_distance; /// let dist = haversine_distance(50.0, 4.0, 50.1, 4.1); /// assert!(dist > 0.0); /// ``` pub fn haversine_distance(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 { // implementation }
# All tests
cargo test --workspace --all-features
# Specific test
cargo test test_haversine_distance
# With output
cargo test -- --nocapture
# Doc tests only
cargo test --doc
# Integration tests only
cargo test --test integration
# Benchmarks
cargo bench --workspace- Add rustdoc comments to all public APIs
- Include examples in doc comments
- Explain complex algorithms
- Document panics, errors, and edge cases
Example:
/// Projects a GNSS position onto the nearest railway netelement.
///
/// # Arguments
///
/// * `position` - The GNSS position to project
/// * `network` - The railway network with spatial index
///
/// # Returns
///
/// Returns `Ok(ProjectedPosition)` on success, or `Err(ProjectionError)`
/// if projection fails.
///
/// # Example
///
/// ```
/// use tp_lib_core::{GnssPosition, RailwayNetwork, project_position};
///
/// let position = GnssPosition::new(50.8503, 4.3517, "2024-01-01T12:00:00+00:00");
/// let network = RailwayNetwork::from_geojson("network.geojson")?;
/// let projected = project_position(&position, &network)?;
/// ```
pub fn project_position(
position: &GnssPosition,
network: &RailwayNetwork,
) -> Result<ProjectedPosition, ProjectionError> {
// implementation
}# Generate docs
cargo doc --workspace --no-deps
# Open in browser
cargo doc --workspace --no-deps --openDocumentation is automatically deployed to GitHub Pages on every push to main.
Releases are automated via GitHub Actions. See docs/WORKFLOWS.md for details.
For Maintainers Only:
- Update versions in all
Cargo.tomlandpyproject.tomlfiles - Update CHANGELOG.md with release notes
- Commit and tag:
git commit -am "chore: release v1.0.0" git tag v1.0.0 git push origin main git push origin v1.0.0 - Create GitHub Release at: https://github.com/matdata-eu/tp-lib/releases/new
- Tag:
v1.0.0 - Title:
Release 1.0.0 - Description: Copy from CHANGELOG.md
- Click "Publish release"
- Tag:
Automated Actions:
- ✅ Publishes
tp-core,tp-cli,tp-pyto crates.io - ✅ Publishes
tp-libPython package to PyPI - ✅ Builds wheels for Linux, Windows, macOS
- ✅ Updates documentation on GitHub Pages
tp-lib/
├── .github/workflows/ # CI/CD automation
├── tp-core/ # Core library
│ ├── src/
│ │ ├── models/ # Data models
│ │ ├── projection/ # Projection algorithms
│ │ ├── path/ # Train path calculation
│ │ ├── io/ # Input/output parsers
│ │ ├── crs/ # Coordinate transformations
│ │ └── temporal/ # Timezone utilities
│ ├── tests/ # Integration tests
│ └── benches/ # Performance benchmarks
├── tp-cli/ # Command-line interface
└── tp-py/ # Python bindings
└── python/tests/ # Python tests
When working on path calculation features (tp-core/src/path/):
The path calculation module consists of several submodules:
candidate.rs: Find candidate netelements for each GNSS positionprobability.rs: Calculate HMM-related probabilities (e.g., emission/transition) using distance, heading, and network contextviterbi.rs: Run the HMM/Viterbi algorithm to compute the most likely train path from the candidate sequencesgraph.rs: Network topology graph operationsspacing.rs: GNSS resampling for consistent spacing
// Main entry point
calculate_train_path(gnss_positions, netelements, netrelations, config) -> PathResult
// Project onto pre-calculated path
project_onto_path(gnss_positions, path, netelements, config) -> Vec<ProjectedPosition>-
Candidate Selection (
find_candidate_netelements)- Uses R-tree spatial index for O(log n) lookup
- Filters by
cutoff_distanceandmax_candidates
-
Probability Calculation (
calculate_combined_probability)- Distance probability:
exp(-distance / distance_scale) - Heading probability:
exp(-heading_diff / heading_scale) - Combined:
distance_prob * heading_prob
- Distance probability:
-
Path Construction (
construct_forward_path,construct_backward_path)- Traverses network using netrelations (topology)
- Builds path in both directions for validation
-
Path Selection (
select_best_path)- Validates bidirectional agreement
- Returns highest probability path
# Run path calculation tests
cargo test --workspace path
# Run integration tests
cargo test --test tests path_calculation
# Run benchmarks
cargo bench --bench projection_bench
cargo bench --bench naive_baseline_benchcargo llvm-cov --lib -p tp-lib-core --html --output-dir target/coverage- SC-001: 1000 positions × 50 netelements in <10 seconds
- Current: ~900μs (11,000× faster than target)
- Memory: <500MB for 10k+ positions
| Parameter | Default | Purpose |
|---|---|---|
distance_scale |
10.0 | Distance decay rate (meters) |
heading_scale |
2.0 | Heading decay rate (degrees) |
cutoff_distance |
500.0 | Max search distance (meters) |
heading_cutoff |
10.0 | Max heading difference (degrees) |
probability_threshold |
0.02 | Min probability for inclusion |
max_candidates |
3 | Max candidates per position |
resampling_distance |
None | Optional GNSS resampling |
TP-Lib follows strict architectural principles (see Constitution v1.1.0):
- Library-First: Core functionality in library, not CLI
- CLI Mandatory: All features accessible via command-line
- High Performance: Use efficient data structures (R-tree, Arrow)
- TDD: Test-driven development, write tests first
- Full Coverage: Comprehensive test suite
- Timezone Awareness: All timestamps with explicit timezone
- CRS Explicit: All coordinates include CRS specification
- Error Handling: Typed errors, fail-fast validation
- Data Provenance: Preserve original data, enable auditing
- Integration Flexibility: Rust API + CLI + Python bindings
- Documentation: https://matdata-eu.github.io/tp-lib/
- Issues: https://github.com/matdata-eu/tp-lib/issues
- Discussions: https://github.com/matdata-eu/tp-lib/discussions
By contributing, you agree that your contributions will be licensed under the Apache License 2.0.
Thank you for contributing to TP-Lib! 🚄