Files
ForgeLM/.agents/rules/project-structure-rust-cargo.md
T

9.0 KiB

trigger, description
trigger description
model_decision When working on a Rust or Cargo project, setting up Rust project structure, or organizing Rust crates and workspaces

Rust/Cargo Layout

Use these structures for Rust projects. The vertical slice principle applies — features are modules, not layers.

Single Binary Crate

For CLI tools, standalone servers, and single-purpose applications.

  project-root/
    Cargo.toml                        # Package manifest + dependencies
    build.rs                          # Build script (optional — for FFI, codegen)
    src/
      main.rs                        # Entry point: CLI parsing, server startup, wires dependencies
      lib.rs                         # Library root — re-exports public modules (enables integration testing)

      # --- Foundational Concerns (The "Platform") ---
      config.rs                      # Configuration loading (env vars, config files)
      error.rs                       # Application-wide error types (thiserror enum)
      telemetry.rs                   # Tracing/logging setup (tracing, tracing-subscriber)

      # --- Business Features (Vertical Slices) ---
      features/
        mod.rs                       # Re-exports feature modules
        task/
          mod.rs                     # Public API of this feature — re-exports types + service
          service.rs                 # Feature service (business logic orchestration)
          logic.rs                   # Pure business rules (no I/O, easily testable)
          models.rs                  # Domain structs (Task, NewTaskRequest)
          error.rs                   # Feature-specific error types
          repository.rs              # Storage trait definition
          postgres.rs                # Postgres implementation of repository trait
          mock.rs                    # Mock implementation for testing
        auth/
          mod.rs
          service.rs
          logic.rs
          models.rs
          ...

      # --- Delivery Layer (HTTP/gRPC) ---
      handlers/
        mod.rs
        task_handler.rs              # HTTP handlers for task feature (axum/actix extractors)
        auth_handler.rs
      router.rs                      # Route definitions, middleware stack

    tests/                           # Integration tests (compiled as separate crate, access only pub API)
      common/
        mod.rs                       # Shared test fixtures, helpers, test database setup
      task_api_test.rs               # Full API integration tests
      auth_flow_test.rs

    benches/                         # Benchmarks (criterion)
      task_benchmark.rs

Key Rust conventions:

  • src/lib.rs + src/main.rs — enables integration testing against lib.rs public API
  • mod.rs re-exports — each feature's mod.rs is its public boundary
  • error.rs per feature — typed errors with thiserror, composed at app level with #[from]
  • tests/ directory — integration tests see only the public API, enforcing encapsulation
  • No controllers/ or services/ at the top level — features are the top-level organization

Library Crate

For publishable libraries, SDKs, and reusable components.

  project-root/
    Cargo.toml                        # Package manifest (lib target)
    src/
      lib.rs                         # Crate root — public API surface, module re-exports
      parser.rs                      # Public module
      ast.rs                         # Public module
      error.rs                       # Public error types (thiserror)
      internal/                      # Private implementation details
        mod.rs
        optimizer.rs
        cache.rs

    examples/                        # Runnable examples (cargo run --example)
      basic_usage.rs
      advanced_config.rs

    tests/                           # Integration tests
      parsing_test.rs

    benches/                         # Benchmarks
      parser_benchmark.rs

Cargo Workspace (Multi-Crate)

For complex projects with multiple internal crates. This is the recommended structure for projects where distinct subsystems benefit from separate compilation units and explicit dependency boundaries.

  project-root/
    Cargo.toml                        # [workspace] manifest — lists all members
    Cargo.lock                        # Locked dependency versions (committed for binaries)

    crates/
      myapp/                          # Main binary crate (entry point, wiring)
        Cargo.toml                    # Depends on other workspace crates
        src/
          main.rs                    # CLI parsing, server setup
          lib.rs
          config.rs
          error.rs
          api/                       # API / protocol handling
            mod.rs
            routes.rs                # Route definitions
            handlers.rs              # Request handlers

      myapp-parser/                   # Domain-specific engine crate
        Cargo.toml
        build.rs                     # Build script (optional — for FFI, codegen)
        src/
          lib.rs
          parser.rs                  # Core parsing logic
          transform.rs               # Data transformations
          cache.rs                   # Caching layer
        tests/                       # Per-crate integration tests (public API only)
          parser_integration.rs

      myapp-client/                   # External service client crate
        Cargo.toml
        src/
          lib.rs
          client.rs                  # Client implementation
          lifecycle.rs               # Connection management
          retry.rs                   # Retry and resilience logic

      myapp-search/                   # Search / query engine crate
        Cargo.toml
        src/
          lib.rs
          search.rs                  # Search implementation
          filter.rs                  # Result filtering
        tests/                       # Per-crate integration tests
          search_integration.rs

      myapp-common/                   # Shared types and utilities
        Cargo.toml
        src/
          lib.rs
          types.rs                   # Shared domain types
          error.rs                   # Common error types
        tests/                       # Per-crate integration tests
          common_integration.rs

    tests/                           # Workspace-level integration tests
      integration/
        full_pipeline_test.rs        # End-to-end tests across crates

    config/                          # Default configuration
      myapp.config.default.json

Key differences from Go/Node layouts:

  • crates/ replaces apps/ — Cargo workspace with explicit inter-crate dependencies in Cargo.toml
  • Each crate has its own Cargo.toml — dependencies are scoped, compile separately, enforces boundaries
  • build.rs — Rust-specific build script for FFI compilation (C grammars for tree-sitter)
  • Cargo.lock committed — standard practice for binary projects (not for library crates)
  • No node_modules/, vendor/ — dependencies are managed by Cargo globally in ~/.cargo/
  • Feature flags in Cargo.toml — use [features] for optional functionality instead of build-time env vars

Test Organization in Rust

Rust has a compiler-enforced two-tier test system that differs fundamentally from Go/TS:

Unit Tests — Inline (Not Separate Files)

  • Convention: #[cfg(test)] mod tests block at the bottom of each .rs file
  • Tests are compiled conditionally — stripped from production builds
  • Can access private functions via use super::*
  • This is NOT a shortcut — it is the official, idiomatic Rust convention
  • Do NOT create separate *_test.rs files for unit tests

Integration Tests — tests/ Directory

  • Location: tests/ directory at each crate's root (next to src/)
  • Each .rs file in tests/ is compiled as its own separate crate
  • Can only access the crate's public API (use my_crate::...)
  • No #[cfg(test)] needed — Cargo treats tests/ as test-only automatically
  • Shared test helpers go in tests/common/mod.rs (not tests/common.rs)

Workspace-level tests:

  • For cross-crate integration / E2E tests, place in tests/ at the workspace root
  • Or create a dedicated test crate in the workspace (e.g. tests-integration/ — tokio pattern)

Example per-crate layout with tests:

crates/pathfinder-search/
  Cargo.toml
  src/
    lib.rs                  # Contains #[cfg(test)] mod tests { ... } at bottom
    search.rs               # Contains #[cfg(test)] mod tests { ... } at bottom
    filter.rs               # Contains #[cfg(test)] mod tests { ... } at bottom
    mock.rs                 # Mock implementations
  tests/                    # Integration tests (separate crate, public API only)
    search_integration.rs   # Tests search through public lib.rs API
    common/
      mod.rs                # Shared test fixtures and helpers
  • Project Structure @project-structure.md (core philosophy)
  • Rust Idioms and Patterns @rust-idioms-and-patterns.md