Understanding the Seam Architecture in pgrust: Breaking Dependency Cycles with Compile-Time Indirection

The seam architecture in pgrust uses compile-time indirection through the seam! macro to replace direct function calls with runtime-filled slots, breaking circular dependencies by separating interface declarations from implementations.

The pgrust project (malisper/pgrust) reimplements PostgreSQL in Rust while maintaining a strictly acyclic crate dependency graph. To solve the tight coupling inherent in database systems—where modules often need to call each other—the codebase employs a novel seam architecture that shifts linkage from compile-time to runtime without sacrificing type safety or performance.

What Is the Seam Architecture in pgrust?

The Core Concept: Compile-Time Indirection

A seam is a compile-time indirection point that replaces a direct function call with a slot that can be filled at runtime. In pgrust, the seam! macro—defined in [crates/_support/seam/seam_core/src/lib.rs](https://github.com/malisper/pgrust/blob/main/crates/_support/seam/seam_core/src/lib.rs)—expands to a module containing three public items:

  • set(f) – Installs the concrete implementation. Can only be called once.
  • call(..) – Invokes the installed implementation; panics if the seam is not yet initialized.
  • is_installed() – Returns whether a concrete implementation has been registered.

This mechanism allows crates to agree on function signatures at compile time while deferring the actual dependency linking until program startup.

How the Seam Architecture Breaks Dependency Cycles

The architecture eliminates circular dependencies through a four-step ownership pattern that separates contracts from implementations.

Step 1: Separate Seams Crates

For any crate X that needs to expose functions externally, a companion crate X-seams is created. This crate contains only seam! declarations and never depends on the concrete implementation of X. For example, port_pqsignal_seams declares signal-handling slots without importing the actual signal implementation.

Step 2: Implementation Crates Depend on Their Own Seams

The original crate X adds a dependency on X-seams and installs its implementation inside an init_seams() function. In [crates/port/port_pqsignal/src/lib.rs](https://github.com/malisper/pgrust/blob/main/crates/port/port_pqsignal/src/lib.rs), the initialization looks like this:

pub fn init_seams() {
    port_pqsignal_seams::pqsignal::set(pqsignal_be);
}

This allows the implementation to reside in the original crate while remaining invisible to consumers at compile time.

Step 3: Consumers Call Through the Seam

Consumer crates depend only on the lightweight X-seams crate, not on X itself. They invoke functionality through the seam slot:

use port_pqsignal_seams::pqsignal;

fn handle_signal() {
    // Calls the implementation installed by port_pqsignal
    pqsignal::call(signal_number);
}

Because the consumer only sees the seam declaration in [port_pqsignal_seams/src/lib.rs](https://github.com/malisper/pgrust/blob/main/crates/port/port_pqsignal_seams/src/lib.rs), the build graph remains acyclic.

Step 4: Runtime Initialization with seams-init

The special seams-init crate orchestrates startup. It iterates over all crates in the workspace and invokes each init_seams() exactly once before any consumer code runs. The init runtime is defined in [crates/_support/seam/init/src/lib.rs](https://github.com/malisper/pgrust/blob/main/crates/_support/seam/init/src/lib.rs).

This produces a unidirectional dependency graph:


consumer ─► X-seams ─► (runtime) X (installs)
        ↘︎                 ↗︎
         ──────► seams-init (calls X::init_seams())

Practical Example: Implementing a Seam in pgrust

Declaring the Seam

First, create a -seams crate that declares the interface:

// crates/myfeature_seams/src/lib.rs
seam_core::seam!(
    /// Executes the core logic of MyFeature.
    pub fn do_work(arg: i32) -> i32
);

Installing the Implementation

The owning crate implements the logic and registers it during initialization:

// crates/myfeature/src/lib.rs
pub fn init_seams() {
    myfeature_seams::do_work::set(|arg| arg * 2); // concrete implementation
}

Calling from Consumer Code

Downstream crates depend only on myfeature_seams, not myfeature:

// crates/consumer/src/lib.rs
use myfeature_seams::do_work;

pub fn run() -> i32 {
    // Panics if myfeature::init_seams() has not been called yet.
    do_work::call(21)
}

Orchestrating Startup

Finally, ensure all seams are installed before use:

// crates/seams_init/src/lib.rs
pub fn init_all() {
    myfeature::init_seams();   // repeat for each crate that owns seams
    // … other init_seams() calls …
}

Running seams_init::init_all() at program entry guarantees that do_work::call executes safely.

Key Source Files in the pgrust Seam Architecture

Summary

  • The seam architecture in pgrust replaces direct function calls with runtime-filled slots declared via the seam! macro.
  • Dependency cycles break by separating interface declarations (X-seams crate) from implementations (X crate).
  • Consumers depend only on lightweight seams crates, never on the concrete implementations.
  • Initialization happens once at startup via the seams-init crate, which calls each module's init_seams() function before any consumer code executes.
  • The pattern keeps the Rust build graph strictly acyclic while preserving zero-cost runtime performance.

Frequently Asked Questions

What happens if a seam is called before initialization?

The call() function will panic at runtime if invoked before the corresponding set() has been called. This is by design—the seams-init crate guarantees that all init_seams() functions run before any consumer code, making this panic a safety net for initialization ordering bugs rather than an expected runtime path.

Why not use trait objects or dependency injection instead of seams?

Trait objects require dyn dispatch and boxing, which introduces vtable overhead and allocation complexity. The seam architecture uses static dispatch through function pointers filled at startup, maintaining zero-cost abstraction characteristics while still breaking compile-time cycles. It also integrates cleanly with pgrust's existing C-to-Rust FFI boundaries where trait objects would be cumbersome.

How does the seam! macro work technically?

The seam! macro, defined in [seam_core/src/lib.rs](https://github.com/malisper/pgrust/blob/main/crates/_support/seam/seam_core/src/lib.rs), expands to a module containing a thread-safe static OnceCell or equivalent storage. The set method writes a function pointer into this storage exactly once, while call reads and invokes that pointer. This generates minimal overhead—just a pointer indirection compared to a direct function call.

Can seams be used for async functions?

While the analysis focuses on synchronous signatures, the architecture supports any function type that can be stored as a function pointer or closure. Async seams would require boxing the future or using async fn pointers, which the underlying storage in seam_core accommodates provided the function signature matches the declaration in the -seams crate.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →