fedora-csb-system-manager

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

  1. Use black_box: Prevent compiler optimization
  2. Warmup iterations: Let CPU caches warm up
  3. Save baselines: Compare against previous runs
  4. Statistical rigor: Criterion provides this
  5. 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

  1. Follow semver: Strict semantic versioning
  2. Good documentation: README and rustdoc
  3. Comprehensive tests: All features tested
  4. Clear license: MIT OR Apache-2.0 is common
  5. Meaningful keywords: Help discoverability
  6. 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

  1. Consistent naming: workspace-package pattern
  2. Shared dependencies: Use workspace.dependencies
  3. Version sync: Use version.workspace = true
  4. One lock file: Shared across workspace
  5. Logical separation: Each crate has clear purpose
  6. Avoid circular deps: Keep dependency graph acyclic