Contributing
Development workflow
# Build
cargo build --workspace
# Test
cargo test --workspace
# Lint (warnings are errors)
cargo clippy --workspace --all-targets -- -D warnings
# Format
cargo fmt --all
Pre-commit hooks
Pre-commit runs on every commit:
cargo fmt— formatting checkcargo clippy— lint with warnings as errorscargo test— full test suite
All three must pass before the commit is created.
Testing
Unit tests
Each crate contains unit tests alongside the source code. Run with:
cargo test -p calculon-costing
cargo test -p calculon-tiles
Integration tests
Integration tests use real Monaco graph tiles committed in test_data/monaco_tiles/. These tiles cover ~32 km² and enable deterministic routing tests.
# Route integration tests
cargo test -p calculon-route --test monaco_route
# Matrix integration tests
cargo test -p calculon-matrix --test monaco_matrix
# HTTP integration tests
cargo test -p calculon --test http_integration
Some tests require France tiles (test_data/france_tiles/) which are not committed to the repository. These tests skip automatically when the tiles are not present.
Project structure
calculon/
├── crates/
│ ├── calculon-core/ # GraphId, PointLL, constants
│ ├── calculon-tiles/ # Tile reader, GraphReader, NodeInfo, DirectedEdge
│ ├── calculon-costing/ # DynamicCost, AutoCost, BicycleCost, PedestrianCost
│ ├── calculon-route/ # Bidirectional A*
│ ├── calculon-matrix/ # CostMatrix
│ └── calculon/ # HTTP server, handlers, maneuvers, narrative
├── test_data/
│ └── monaco_tiles/ # Real tiles for integration tests
├── locales/ # i18n narrative files (36+ languages)
├── tools/
│ └── compare/ # Comparison UI (Lit + MapLibre)
└── docs/ # This documentation (Zensical)
Code conventions
- No
eprintln!— use the logger (log::debug!,log::trace!, etc.) - Graph-walking helpers belong on
GraphReaderincalculon-tiles, not duplicated across crates unsafeis only used in tile parsing with documented bounds checks- Pre-computed lookup tables for O(1) factor lookups — avoid runtime computation in hot paths
spawn_blockingfor all CPU-bound work in HTTP handlers
Benchmarks
# All benchmarks
cargo bench --workspace
# Specific benchmark
cargo bench -p calculon-route -- route_city
cargo bench -p calculon-costing -- edge_cost
Benchmarks use Criterion and require test_data/france_tiles/ for routing benchmarks.
Coverage
# Generate coverage report (requires cargo-llvm-cov)
make coverage
The report is written to lcov-fixed.info (with relative paths for SonarQube compatibility).
SonarQube
Local SonarQube analysis is available via Docker:
# One-time: create the project
make sonar-create-project
# Run analysis with coverage
make sonar
This runs cargo clippy (JSON output), generates LCOV coverage, and launches the SonarQube scanner. Results are available at http://localhost:9000.
Quality gates target: zero bugs, zero vulnerabilities, zero code smells, coverage >= 80%.
Debugging
Logging
Use RUST_LOG to control log output:
# Route-level debug logging
RUST_LOG=calculon_route=debug calculon --tile-dir ./tiles
# Costing trace logging
RUST_LOG=calculon_costing=trace calculon --tile-dir ./tiles
# Everything
RUST_LOG=debug calculon --tile-dir ./tiles
Always use log::debug!, log::trace!, etc. — never eprintln!.
Debug endpoints
Use the debug endpoints to inspect graph state at specific locations:
# Inspect all edges at a junction
curl -s http://localhost:8002/debug/inspect \
-d '{"lat": 43.611, "lon": 3.862}' | jq
# Cost breakdown from a specific edge
curl -s http://localhost:8002/debug/cost \
-d '{"from_edge_id": "2/751073/456"}' | jq
# Verbose route with per-edge costs
curl -s http://localhost:8002/route \
-d '{"locations": [{"lat":43.62,"lon":3.84},{"lat":43.60,"lon":3.88}], "verbose": true}' \
| jq '.trip.legs[0].debug_edges'
See API Endpoints for full request/response formats.
Comparison tool
For side-by-side comparison with Valhalla, use the comparison tool:
./tools/compare/run.sh --tiles france
Obtaining tiles
Monaco (test tiles)
Monaco tiles are committed in test_data/monaco_tiles/ — no extra setup needed.
France tiles
France tiles are used for benchmarks and integration tests but are not committed to the repo:
# Generate from OSM data (requires Docker)
make tiles
This runs the Valhalla tile builder on a France OSM extract and writes tiles to test_data/france_tiles/.
Custom regions
To generate tiles for any region:
- Download an OSM extract (
.osm.pbf) from Geofabrik - Run the Valhalla tile builder:
docker run -v /path/to/data:/data ghcr.io/valhalla/valhalla:latest \ valhalla_build_tiles -c /data/valhalla.json /data/extract.osm.pbf - Point Calculon at the output directory:
calculon --tile-dir /path/to/tiles
Rustdoc
Generate API documentation for all crates:
cargo doc --workspace --no-deps --open
All public types, traits, and functions are documented. Tile format structs include binary layout comments.