Advanced Rust Workflows
This reference consolidates advanced Rust development workflows that are used less frequently.
Core workflows (used frequently) are in separate workflow files:
- Build (workflows/Build.md)
- Test (workflows/Test.md)
- Deps (workflows/Deps.md)
- Lint (workflows/Lint.md)
- Error (workflows/Error.md)
Bench - Benchmarking and Performance
Benchmark Rust code with Criterion.
When to Use
- “benchmark”
- “cargo bench”
- “performance test”
- “criterion”
Setup
[dev-dependencies]
criterion = { version = "0.7", features = ["html_reports"] }
[[bench]]
name = "my_benchmark"
harness = false
Quick Commands
# Run benchmarks
cargo bench
# Run specific benchmark
cargo bench my_function
# Save baseline
cargo bench -- --save-baseline main
# Compare to baseline
cargo bench -- --baseline main
Basic Benchmark
// benches/my_benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci(n-1) + fibonacci(n-2),
}
}
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
Parametrized Benchmarks
use criterion::{BenchmarkId, Criterion};
fn bench_sizes(c: &mut Criterion) {
let mut group = c.benchmark_group("sizes");
for size in [10, 100, 1000].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(size),
size,
|b, &size| {
b.iter(|| process_data(black_box(size)))
},
);
}
group.finish();
}
Comparing Functions
fn bench_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("algorithms");
group.bench_function("algorithm_a", |b| {
b.iter(|| algorithm_a(black_box(&data)))
});
group.bench_function("algorithm_b", |b| {
b.iter(|| algorithm_b(black_box(&data)))
});
group.finish();
}
Best Practices
- Use
black_box: Prevent compiler optimization - Warmup iterations: Let CPU caches warm up
- Save baselines: Compare against previous runs
- Statistical rigor: Criterion provides this
- Profile first: Use profilers before micro-benchmarks
Publish - Publishing to crates.io
Publish Rust crates to crates.io.
When to Use
- “publish crate”
- “cargo publish”
- “crates.io”
Preparation
1. Get API Token
# Login to crates.io
cargo login
# Or set token manually
cargo login <your-api-token>
2. Configure Cargo.toml
[package]
name = "my-awesome-crate"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
description = "A short description of your crate"
documentation = "https://docs.rs/my-awesome-crate"
repository = "https://github.com/user/my-awesome-crate"
license = "MIT OR Apache-2.0"
keywords = ["cli", "tool", "utility"] # Max 5
categories = ["command-line-utilities"]
readme = "README.md"
# Important: exclude large or unnecessary files
exclude = [
"/.github",
"/target",
"*.png",
"benches/",
]
Publishing
# Dry run (test package)
cargo publish --dry-run
# Package and inspect
cargo package --list
# Publish
cargo publish
# Publish with custom registry
cargo publish --registry my-registry
Version Management
# Update version in Cargo.toml
# Use semantic versioning: MAJOR.MINOR.PATCH
# Tag release
git tag v0.1.0
git push --tags
Semantic Versioning
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
0.1.0 -> 0.1.1 (bug fix)
0.1.1 -> 0.2.0 (new feature)
0.2.0 -> 1.0.0 (breaking change)
Yanking Versions
# Yank a version (prevent new dependents)
cargo yank --vers 0.1.0
# Un-yank
cargo yank --vers 0.1.0 --undo
Pre-Publish Checklist
- Update version in Cargo.toml
- Update CHANGELOG.md
- Run
cargo test --all-features - Run
cargo clippy --all-targets - Run
cargo doc --no-deps - Verify README.md is up to date
- Check license files present
- Run
cargo publish --dry-run - Tag release in git
- Publish to crates.io
Best Practices
- Follow semver: Strict semantic versioning
- Good documentation: README and rustdoc
- Comprehensive tests: All features tested
- Clear license: MIT OR Apache-2.0 is common
- Meaningful keywords: Help discoverability
- Keep it small: Exclude unnecessary files
Workspace - Cargo Workspace Management
Manage multi-crate projects with Cargo workspaces.
When to Use
- “cargo workspace”
- “multi-crate project”
- “monorepo”
Structure
myworkspace/
├── Cargo.toml # Workspace root
├── Cargo.lock # Shared lock file
├── crates/
│ ├── core/
│ │ ├── Cargo.toml
│ │ └── src/lib.rs
│ ├── cli/
│ │ ├── Cargo.toml
│ │ └── src/main.rs
│ └── api/
│ ├── Cargo.toml
│ └── src/lib.rs
Root Cargo.toml
[workspace]
members = [
"crates/*",
]
exclude = ["crates/experimental"]
# Use Rust 2024 resolver
resolver = "3"
# Shared dependencies
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
# Shared metadata
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["Your Name <you@example.com>"]
# Shared lints
[workspace.lints.rust]
unsafe_code = "forbid"
[workspace.lints.clippy]
pedantic = "warn"
Member Cargo.toml
[package]
name = "myworkspace-cli"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
# Workspace dependencies
serde.workspace = true
tokio.workspace = true
# Internal dependencies
myworkspace-core = { path = "../core" }
# Member-specific dependencies
clap = "4.0"
Commands
# Build entire workspace
cargo build --workspace
# Build specific package
cargo build -p myworkspace-cli
# Test all packages
cargo test --workspace
# Test specific package
cargo test -p myworkspace-core
# Run binary from package
cargo run -p myworkspace-cli
# Check all packages
cargo check --workspace
Best Practices
- Consistent naming:
workspace-packagepattern - Shared dependencies: Use
workspace.dependencies - Version sync: Use
version.workspace = true - One lock file: Shared across workspace
- Logical separation: Each crate has clear purpose
- Avoid circular deps: Keep dependency graph acyclic