<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dmytro Brazhnyk</title>
    <description>The latest articles on DEV Community by Dmytro Brazhnyk (@dmytro_brazhyk).</description>
    <link>https://dev.to/dmytro_brazhyk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3862812%2F69db82df-4269-453d-b314-c27e07b9ec84.png</url>
      <title>DEV Community: Dmytro Brazhnyk</title>
      <link>https://dev.to/dmytro_brazhyk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dmytro_brazhyk"/>
    <language>en</language>
    <item>
      <title>Can Rust Have Zero-Cost Dependency Injection?</title>
      <dc:creator>Dmytro Brazhnyk</dc:creator>
      <pubDate>Thu, 09 Apr 2026 18:07:20 +0000</pubDate>
      <link>https://dev.to/dmytro_brazhyk/can-rust-have-zero-cost-dependency-injection-4960</link>
      <guid>https://dev.to/dmytro_brazhyk/can-rust-have-zero-cost-dependency-injection-4960</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This article explores whether dependency injection (DI) can exist in Rust without sacrificing the language’s core philosophy of zero-cost abstractions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ibgkb3oij74beo49hbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ibgkb3oij74beo49hbe.png" alt="Rust dependency injection picture" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will approach the question from three angles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why dependency injection still matters in Rust, even for systems built with zero-sized types and compile-time guarantees.&lt;/li&gt;
&lt;li&gt;How DI evolved in other ecosystems, using Java as a reference point.&lt;/li&gt;
&lt;li&gt;A practical Rust-oriented approach to implementing DI with compile-time guarantees.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;“We’ll also show how Rust traits enable DI patterns that scale across crates, preserving zero-cost guarantees.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All Rust source code used in this article is available in the repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/amidukr/rust-dependency-injection-example" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Rust DI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem Rust Hasn’t Solved Yet
&lt;/h3&gt;

&lt;p&gt;Rust has solved problems most languages haven’t even dared to touch: memory safety without a garbage collector, fearless concurrency, and powerful zero-cost abstractions.&lt;/p&gt;

&lt;p&gt;But there is a class of problems Rust hasn’t fully confronted yet.&lt;/p&gt;

&lt;p&gt;Not because Rust is incapable — but because these problems exist &lt;strong&gt;above the machine level&lt;/strong&gt;. They are not about memory safety or performance. They are about &lt;strong&gt;composition, modularity, and architectural correctness in large systems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Managing dependencies between dozens or hundreds of components is fundamentally different from managing memory or threads. Rust gives us powerful primitives, but the question remains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we scale composition safely and maintainably?&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  What “Enterprise” Really Means in Rust Terms
&lt;/h3&gt;

&lt;p&gt;When Rust developers hear enterprise, they often think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;slow, over-engineered, bloated&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But that perception is misleading.&lt;/p&gt;

&lt;p&gt;Enterprise systems are not bloated by accident. They are complex because &lt;strong&gt;composition eventually stops being trivial.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2jazu7t0srbtvbz7hm5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2jazu7t0srbtvbz7hm5c.png" alt="The problem Rust Hasn't Solvet Yet" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complexity comes from business requirements, not from the technology stack.&lt;/p&gt;




&lt;h3&gt;
  
  
  Enterprise: The Burden We Can’t Avoid
&lt;/h3&gt;

&lt;p&gt;When a company reaches a certain scale, several things inevitably happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Products serve thousands or millions of users&lt;/li&gt;
&lt;li&gt;Systems integrate with vendors, partners, and third-party services&lt;/li&gt;
&lt;li&gt;Teams work independently on modules and features&lt;/li&gt;
&lt;li&gt;Software must evolve continuously without stopping the business&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These realities create architectural pressure.&lt;/p&gt;

&lt;p&gt;From a technical perspective, systems must support:&lt;/p&gt;

&lt;h4&gt;
  
  
  Scalability
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;At multiple levels&lt;/strong&gt; — both in terms of &lt;strong&gt;users and data:&lt;/strong&gt; including &lt;strong&gt;hundreds, thousands, or millions or even up to billion of concurrent users&lt;/strong&gt;, as well as functional modules interacting across teams.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reliability
&lt;/h4&gt;

&lt;p&gt;Systems run 24/7. Services must handle failures, because dependencies on vendors, partners, or third-party services mean that failures are inevitable, and the system must continue operating despite them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Modularity
&lt;/h4&gt;

&lt;p&gt;Independent teams need to work on isolated components without breaking other parts of the system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Flexibility
&lt;/h4&gt;

&lt;p&gt;Infrastructure choices may change. Databases, messaging systems, or integrations might need to be swapped without rewriting the entire application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Observability
&lt;/h4&gt;

&lt;p&gt;To detect and respond to performance bottlenecks, integration failures, or unexpected behaviors quickly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Extensibility
&lt;/h4&gt;

&lt;p&gt;New products, markets, and regulations require systems to evolve incrementally rather than being rebuilt from scratch.&lt;/p&gt;

&lt;h4&gt;
  
  
  Maintainable
&lt;/h4&gt;

&lt;p&gt;Every business decision introduces new dependencies. And every dependency increases the complexity of the system’s composition.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Ensuring that the system doesn’t become so convoluted that small changes introduce cascading errors.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Even with Rust’s ownership model and strong type system, &lt;strong&gt;manually managing this dependency graph eventually becomes impractical.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These pressures are not theoretical — they define &lt;strong&gt;the daily reality of enterprise software engineering.&lt;/strong&gt; Every design decision must balance &lt;strong&gt;immediate business needs&lt;/strong&gt; with &lt;strong&gt;long-term sustainability,&lt;/strong&gt; especially under &lt;strong&gt;high concurrent load.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Dependency Injection Becomes Relevant
&lt;/h3&gt;

&lt;p&gt;This is exactly where dependency injection becomes useful.&lt;/p&gt;

&lt;p&gt;DI allows systems to manage complexity by separating &lt;strong&gt;what components&lt;/strong&gt; need from &lt;strong&gt;how those dependencies are created and connected.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In practice, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components declare their dependencies without constructing them directly&lt;/li&gt;
&lt;li&gt;Dependencies are provided externally, keeping components isolated&lt;/li&gt;
&lt;li&gt;Systems evolve gradually without breaking existing modules&lt;/li&gt;
&lt;li&gt;Optional features and plugins can be integrated without tightly coupling the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DI is not just a convenience. It is a structured approach to handling &lt;strong&gt;inevitable architectural complexity&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Enterprise Isn’t Just Complexity — It’s Heterogeneity
&lt;/h3&gt;

&lt;p&gt;Large systems are rarely uniform.&lt;/p&gt;

&lt;p&gt;They typically contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Independent components with their own dependency trees&lt;/li&gt;
&lt;li&gt;Stateful infrastructure such as databases, caches, and message brokers&lt;/li&gt;
&lt;li&gt;Optional features and plugin-style modules&lt;/li&gt;
&lt;li&gt;Multiple implementations of the same interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This heterogeneity appears naturally over time.&lt;/p&gt;

&lt;p&gt;Systems accumulate tools built years apart, libraries maintained by different teams, and components that survive long after their original authors have moved on.&lt;/p&gt;

&lt;p&gt;Enterprise systems grow gradually, and they rarely get the chance to start over.&lt;/p&gt;

&lt;p&gt;Rust does not eliminate these pressures. Any real system eventually faces them.&lt;/p&gt;




&lt;h3&gt;
  
  
  Java’s Historical Perspective: DI Was Inevitable
&lt;/h3&gt;

&lt;p&gt;Java did not adopt dependency injection because it was fashionable.&lt;/p&gt;

&lt;p&gt;It adopted DI because large systems were becoming impossible to manage without it.&lt;/p&gt;

&lt;p&gt;Without DI, developers quickly ran into familiar problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tight coupling between components&lt;/li&gt;
&lt;li&gt;Fragile initialization order&lt;/li&gt;
&lt;li&gt;Hard-coded dependencies scattered across the codebase&lt;/li&gt;
&lt;li&gt;Changes in one module unexpectedly breaking another&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dependency injection emerged as a &lt;strong&gt;discipline for managing complexity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Components declare what they depend on, and the system provides those dependencies when constructing the application.&lt;/p&gt;

&lt;p&gt;This separation allows systems to evolve without collapsing under their own architecture.&lt;/p&gt;




&lt;h3&gt;
  
  
  DI in a Nutshell
&lt;/h3&gt;

&lt;p&gt;You can think of dependency injection as a kind of &lt;strong&gt;runtime composition system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your application contains many services, modules, plugins, or optional components, something must assemble them and ensure they are wired correctly and that role belongs to the DI system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fl8491l8p6gogpgzwqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fl8491l8p6gogpgzwqm.png" alt="DI in a Nuthsell" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DI is conceptually similar to package managers such as Cargo or Maven, but it operates at a different level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Package managers&lt;/strong&gt; resolve dependencies between libraries at build time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency injection&lt;/strong&gt; resolves dependencies between components at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Loading executable code into memory is easy — the operating system handles that.&lt;/p&gt;

&lt;p&gt;What is harder is creating objects, initializing them correctly, and ensuring that all components interact with the right dependencies.&lt;/p&gt;

&lt;p&gt;This becomes increasingly difficult as systems grow.&lt;/p&gt;

&lt;p&gt;Dependency injection addresses this problem directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Dependency Injection Is Typically Solved in Java
&lt;/h3&gt;

&lt;p&gt;Java provides one of the most mature ecosystems for dependency injection. Frameworks such as Spring or Guice automate object creation and dependency wiring almost entirely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci87b9wppnxo13g27mqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci87b9wppnxo13g27mqh.png" alt="How Dependency Injection Is Typically Solved in Java" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s revisit the same example from the previous section: a simple User Management API.&lt;/p&gt;

&lt;p&gt;We have two controllers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ReadController — retrieves users from a database&lt;/li&gt;
&lt;li&gt;WriteController — creates users and publishes events to a message broker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both controllers depend on infrastructure services that must be created and wired correctly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Without Dependency Injection
&lt;/h4&gt;

&lt;p&gt;In a traditional manual setup, object creation and wiring might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostgresDatabase&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;MessageBroker&lt;/span&gt; &lt;span class="n"&gt;broker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KafkaBroker&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;ReadController&lt;/span&gt; &lt;span class="n"&gt;readController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WriteController&lt;/span&gt; &lt;span class="n"&gt;writeController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WriteController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;broker&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// start application&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance this appears manageable. But as the application grows, the initialization code expands rapidly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple infrastructure services&lt;/li&gt;
&lt;li&gt;optional modules&lt;/li&gt;
&lt;li&gt;configuration logic&lt;/li&gt;
&lt;li&gt;conditional wiring depending on environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; method eventually becomes responsible for constructing the entire dependency graph of the application.&lt;/p&gt;

&lt;p&gt;This approach becomes difficult to maintain and extremely fragile as the system evolves.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dependency Injection with Spring
&lt;/h4&gt;

&lt;p&gt;Dependency injection frameworks solve this by moving the responsibility of object creation and wiring to a container.&lt;/p&gt;

&lt;p&gt;Components simply declare what they need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaBroker&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessageBroker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReadController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ReadController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependencies are declared in constructors, and the DI container automatically provides the correct instances.&lt;/p&gt;

&lt;p&gt;The application no longer manually constructs the object graph. Instead, the framework scans components and resolves dependencies automatically.&lt;/p&gt;




&lt;h4&gt;
  
  
  Polymorphism in Java DI
&lt;/h4&gt;

&lt;p&gt;Java DI frameworks also support &lt;strong&gt;multiple implementations of the same interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, an application may support several message brokers simultaneously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaBroker&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessageBroker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitBroker&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessageBroker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A controller can receive all implementations at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WriteController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MessageBroker&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;brokers&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WriteController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MessageBroker&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;brokers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;brokers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brokers&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DI container automatically collects all implementations of &lt;code&gt;MessageBroker&lt;/code&gt; and injects them into the controller. This makes the system highly extensible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new brokers can be added&lt;/li&gt;
&lt;li&gt;existing ones can be removed&lt;/li&gt;
&lt;li&gt;the controller remains unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Cost of Traditional DI&lt;/p&gt;

&lt;p&gt;Java DI frameworks provide powerful capabilities, but they come with trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependency resolution happens at runtime&lt;/li&gt;
&lt;li&gt;reflection is heavily used&lt;/li&gt;
&lt;li&gt;errors may only appear during application startup&lt;/li&gt;
&lt;li&gt;dependency graphs are not always fully visible to the compiler&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This runtime flexibility works well for the Java ecosystem, but it introduces overhead and reduces compile-time guarantees. Rust, on the other hand, encourages a different philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If something can be verified at compile time, it should be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This raises an interesting question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Rust achieve the same flexibility of dependency injection while preserving compile-time guarantees and zero runtime cost?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey into Rust Coding
&lt;/h2&gt;

&lt;p&gt;Let’s try to build a dependency injection approach in Rust gradually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8p7cspsyp3jdxmmy9b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8p7cspsyp3jdxmmy9b5.png" alt="Journey into Rust Coding" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will follow the same conceptual example used in the Java section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;ReadController&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;WriteController&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;multiple implementations of a &lt;strong&gt;MessageBroker&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;an abstraction for database connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All code used in this article can be found in the repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/amidukr/rust-dependency-injection-example" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Rust Without Dependency Injection
&lt;/h2&gt;

&lt;p&gt;In the first example we will implement a small Rust application &lt;strong&gt;without dependency injection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpktmh13gndmczauiigaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpktmh13gndmczauiigaa.png" alt="No Dependency Injection" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, we will introduce &lt;strong&gt;use-traits&lt;/strong&gt;, which will later allow us to transition naturally to a dependency injection model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/no_di.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/no_di.rs&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Defining Database Interfaces
&lt;/h3&gt;

&lt;p&gt;First, let’s define the interface used to access the database.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1 DatabaseConnection Trait
&lt;/h4&gt;

&lt;p&gt;This trait represents an abstraction for database connectivity that can support multiple implementations (Postgres, MySQL, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1.2 UseDatabaseConnection Trait
&lt;/h4&gt;

&lt;p&gt;Next, we define a trait that allows components to &lt;strong&gt;request a database connection&lt;/strong&gt; from a context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;database_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This trait will later be used as the &lt;strong&gt;foundation of dependency resolution&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of components knowing the entire application context, they simply declare that they require a &lt;strong&gt;DatabaseConnection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This keeps components &lt;strong&gt;decoupled from the full application structure&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Database Implementation
&lt;/h3&gt;

&lt;p&gt;Now we provide a concrete implementation of &lt;strong&gt;DatabaseConnection&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Reading from Postgres DB: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Writing into Postgres DB: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simplicity, this example only prints messages instead of connecting to a real database.&lt;/p&gt;

&lt;p&gt;In a real system this could be implemented using any production database library.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Controllers
&lt;/h3&gt;

&lt;p&gt;Now we define the controllers responsible for performing application logic.&lt;/p&gt;




&lt;h4&gt;
  
  
  3.1 Controller Structs
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ReadController&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;WriteController&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust allows structs with no fields.&lt;/p&gt;

&lt;p&gt;These zero-sized types have no runtime cost, but they still represent concrete types at compile time and can participate in abstractions.&lt;/p&gt;




&lt;h4&gt;
  
  
  3.2 Controller Use Traits
&lt;/h4&gt;

&lt;p&gt;Next we define traits that expose controllers to other components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;UseReadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ReadController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;UseWriteController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;WriteController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These traits allow components to access controllers &lt;strong&gt;without knowing anything about the application context&lt;/strong&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  3.3 Controller Context
&lt;/h4&gt;

&lt;p&gt;Now we combine the previously defined traits into a context trait.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;UseReadController&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;UseWriteController&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This context describes &lt;strong&gt;the minimal environment required for controllers to function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Controllers will depend only on this trait instead of the full application context.&lt;/p&gt;




&lt;h4&gt;
  
  
  3.4 Controller Implementation
&lt;/h4&gt;

&lt;p&gt;Now we implement the controller logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ReadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.database_connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.read_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM table WHERE id = '{}'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;WriteController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.database_connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.write_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UPDATE table SET value = 'new' WHERE id = '{}'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something important here:&lt;/p&gt;

&lt;p&gt;The controllers &lt;strong&gt;do not know about the full application context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They only know about the &lt;strong&gt;traits they depend on&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means the controller and database code could already be extracted into &lt;strong&gt;separate crates&lt;/strong&gt;, reusable by any application implementing the required use-traits.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Wiring the Application
&lt;/h3&gt;




&lt;p&gt;Now we wire all components together.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1 Application Context
&lt;/h4&gt;

&lt;p&gt;We define a struct that holds all application components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;read_controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReadController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;write_controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WriteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;postgres_database_connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This struct acts as the &lt;strong&gt;composition root&lt;/strong&gt; of the application.&lt;/p&gt;




&lt;h4&gt;
  
  
  4.2 Implement Use Traits
&lt;/h4&gt;

&lt;p&gt;Next we implement the previously defined traits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseReadController&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ReadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.read_controller&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseWriteController&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;WriteController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.write_controller&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;database_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.postgres_database_connection&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing these traits, &lt;code&gt;ApplicationContext&lt;/code&gt; becomes capable of &lt;strong&gt;providing dependencies to components&lt;/strong&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  4.3 Controller Context Implementation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;ApplicationContext&lt;/code&gt; already implements the required traits, it automatically satisfies &lt;code&gt;ControllerContext&lt;/code&gt;.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Running the Application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally we run the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ApplicationContext&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.read_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.write_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key characteristics of this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;dyn&lt;/code&gt; traits&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;Arc&lt;/code&gt; or &lt;code&gt;Rc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No runtime dependency container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All wiring is resolved &lt;strong&gt;at compile time&lt;/strong&gt; through generics and monomorphization.&lt;/p&gt;




&lt;h3&gt;
  
  
  Multi-Threading
&lt;/h3&gt;

&lt;p&gt;An attentive reader may ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will this approach work in multi-threaded environments?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe59s5cene62mqsuurgqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe59s5cene62mqsuurgqb.png" alt="Multi-Threading" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Rust, thread safety is typically ensured using the &lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt; traits.&lt;/p&gt;

&lt;p&gt;These traits are automatically implemented by the compiler if &lt;strong&gt;all fields of a struct are also &lt;code&gt;Send + Sync&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;More details can be found in the Rust documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://doc.rust-lang.org/nomicon/send-and-sync.html" rel="noopener noreferrer"&gt;https://doc.rust-lang.org/nomicon/send-and-sync.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can verify thread safety with a compile-time assertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;assert_send_sync&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Sync&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nn"&gt;assert_send_sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this compiles, the entire application context can safely be shared between threads.&lt;/p&gt;

&lt;p&gt;In real systems, some components (such as database connections) may not be inherently thread-safe. In such cases, a &lt;strong&gt;connection pool&lt;/strong&gt; or synchronization mechanisms such as &lt;code&gt;Mutex&lt;/code&gt; are required.&lt;/p&gt;

&lt;p&gt;This limitation is not related to the dependency injection approach itself, but rather to &lt;strong&gt;shared resource management in concurrent systems&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the Compiler Actually Generates
&lt;/h3&gt;

&lt;p&gt;If we inspect the compiled output with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo asm rust_di_example::main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;... 
  26 │  lea     rbx, [rsp, +, 32]
  27 │  mov     rdx, rbx
  28 │  call    qword, ptr, [rip, +, _ZN5alloc3fmt6format12format_inner17he42ed4cf3cdc276bE@GOTPCREL]
  29 │  movups  xmm0, xmmword, ptr, [rsp]
  30 │  mov     rax, qword, ptr, [rsp, +, 16]
  31 │  movups  xmmword, ptr, [rsp, +, 48], xmm0
  32 │  mov     qword, ptr, [rsp, +, 64], rax
  33 │  mov     qword, ptr, [rsp, +, 32], r14
  34 │  mov     qword, ptr, [rsp, +, 40], 18
  35 │  mov     qword, ptr, [rsp], rbx
  36 │  mov     qword, ptr, [rsp, +, 8], r13
  37 │  lea     rdi, [rip, +, .Lanon.63c02f0152e6743e61fdeaf76f1d4051.26]
  38 │  mov     rsi, rsp
  39 │  call    qword, ptr, [rip, +, _ZN3std2io5stdio6_print17hba8f5eda1e4e495eE@GOTPCREL]
  40 │  lea     rax, [rip, +, .Lanon.63c02f0152e6743e61fdeaf76f1d4051.27]
  41 │  mov     qword, ptr, [rsp, +, 32], rax
  42 │  mov     qword, ptr, [rsp, +, 40], 19
  43 │  mov     qword, ptr, [rsp], rbx
  44 │  mov     qword, ptr, [rsp, +, 8], r13
  45 │  lea     r14, [rsp, +, 48]
  46 │  mov     qword, ptr, [rsp, +, 16], r14
  47 │  lea     r15, [rip, +, _ZN60_$LT$alloc..string..String$u20$as$u20$core..fmt..Display$GT$3fmt17h9d11f1d81b352ac8E]
  48 │  mov     qword, ptr, [rsp, +, 24], r15
  49 │  lea     rdi, [rip, +, .Lanon.63c02f0152e6743e61fdeaf76f1d4051.7]
  50 │  mov     rsi, rsp
  51 │  call    qword, ptr, [rip, +, _ZN3std2io5stdio6_print17hba8f5eda1e4e495eE@GOTPCREL]
  52 │  lea     rax, [rip, +, .Lanon.63c02f0152e6743e61fdeaf76f1d4051.28]
  53 │  mov     qword, ptr, [rsp, +, 32], rax
  54 │  mov     qword, ptr, [rsp, +, 40], 21
  55 │  mov     qword, ptr, [rsp], rbx
  56 │  mov     qword, ptr, [rsp, +, 8], r13
  57 │  mov     qword, ptr, [rsp, +, 16], r14
  58 │  mov     qword, ptr, [rsp, +, 24], r15
  59 │  lea     rdi, [rip, +, .Lanon.63c02f0152e6743e61fdeaf76f1d4051.8]
  60 │  mov     rsi, rsp
  61 │  call    qword, ptr, [rip, +, _ZN3std2io5stdio6_print17hba8f5eda1e4e495eE@GOTPCREL]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see extremely &lt;strong&gt;flat assembly code&lt;/strong&gt; with series of invocation to &lt;em&gt;_ZN3std2io5stdio6_print17hba8f5eda1e4e495eE@GOTPCREL&lt;/em&gt; that is just printing subroutine in rust runtime&lt;/p&gt;

&lt;p&gt;There are no runtime dependency resolution mechanisms, no dynamic dispatch, and no container logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjksnciofggilijek7n8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjksnciofggilijek7n8b.png" alt="Compilation, Optimization pipeline" width="720" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated code mostly contains calls to standard library functions such as printing.&lt;/p&gt;

&lt;p&gt;This demonstrates that the abstractions introduced here &lt;strong&gt;do not introduce runtime overhead&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Use-Traits Matter
&lt;/h3&gt;

&lt;p&gt;At first glance, the &lt;code&gt;use-trait&lt;/code&gt; might look like unnecessary indirection.&lt;br&gt;
Why not simply pass &lt;code&gt;ApplicationContext&lt;/code&gt; directly to every component?&lt;/p&gt;

&lt;p&gt;The reason is &lt;strong&gt;crate-level decoupling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Enterprise applications often grow into multiple crates. Controllers, database access layers, messaging integrations, and domain logic are very often implemented as reusable libraries. For example, a Spring Boot actuator–style module may contain all layers inside the DB, provide REST API endpoints, and integrate with a monitoring aggregator service — it acts as a standalone sub-program.&lt;/p&gt;

&lt;p&gt;However, if a component directly depends on &lt;code&gt;ApplicationContext&lt;/code&gt;, it becomes tied to the executable crate that defines it.&lt;/p&gt;

&lt;p&gt;That creates an architectural problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Libraries would depend on the application crate&lt;/li&gt;
&lt;li&gt;The application crate would depend on the libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This circular dependency makes reuse impossible.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Use-trait&lt;/code&gt; solve this by defining &lt;strong&gt;capability-based interfaces&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of depending on the application context, components depend only on the capabilities they require.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;database_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A controller does not know anything about the application structure.&lt;br&gt;
It simply requires that the context provides access to a database connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ReadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.database_connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.read_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM table WHERE id = '{}'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of this design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ReadController&lt;/code&gt; can live in its &lt;strong&gt;own crate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The crate only exports traits describing the &lt;strong&gt;capabilities it needs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Any application can use the controller by implementing those traits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;application context becomes an adapter&lt;/strong&gt;, wiring together independent components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
 ├── implements UseDatabaseConnection
 ├── implements UseReadController
 └── implements UseWriteController
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern enables a powerful architectural property:&lt;/p&gt;

&lt;p&gt;Components become &lt;strong&gt;fully reusable libraries&lt;/strong&gt;, while the application remains responsible only for wiring them together.&lt;/p&gt;

&lt;p&gt;In other words, &lt;strong&gt;use-traits allow dependency injection to cross crate boundaries while preserving Rust’s compile-time guarantees&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Without this indirection, the system collapses into a monolithic application context that cannot be decomposed into reusable modules.&lt;/p&gt;




&lt;h3&gt;
  
  
  Limitations of This Approach
&lt;/h3&gt;

&lt;p&gt;Although this example demonstrates many useful properties, it is &lt;strong&gt;not yet a complete dependency injection system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main limitation is that &lt;code&gt;ApplicationContext&lt;/code&gt; still has &lt;strong&gt;too much knowledge about component internals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In real DI frameworks, modules often contain &lt;strong&gt;many components, initialization logic, and internal dependencies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, consider a Spring Boot module such as &lt;strong&gt;Spring Data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you add the dependency to your project, it automatically provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database driver integration&lt;/li&gt;
&lt;li&gt;connection pooling&lt;/li&gt;
&lt;li&gt;repository interfaces&lt;/li&gt;
&lt;li&gt;transaction management&lt;/li&gt;
&lt;li&gt;entity scanning&lt;/li&gt;
&lt;li&gt;metrics integration&lt;/li&gt;
&lt;li&gt;health check integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this functionality is assembled automatically by the DI framework.&lt;/p&gt;

&lt;p&gt;From the application developer’s perspective, only minimal configuration is required.&lt;/p&gt;

&lt;p&gt;Real dependency injection modules therefore consist of &lt;strong&gt;entire subgraphs of components&lt;/strong&gt;, not just individual services.&lt;/p&gt;

&lt;p&gt;In our example we intentionally introduced two controllers to demonstrate that even a simple module may contain &lt;strong&gt;multiple cooperating components&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A complete dependency injection framework must also manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;module composition&lt;/li&gt;
&lt;li&gt;initialization lifecycle&lt;/li&gt;
&lt;li&gt;dependency resolution&lt;/li&gt;
&lt;li&gt;optional components&lt;/li&gt;
&lt;li&gt;multiple implementations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where the real challenge begins.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rust With Dependency Injection
&lt;/h2&gt;

&lt;p&gt;To implement dependency injection in Rust, we will build &lt;strong&gt;iteratively&lt;/strong&gt;. We start from the previous “no DI” approach and gradually &lt;strong&gt;close the gap toward a complete DI system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hp4vy0uf6s7o54n9pml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hp4vy0uf6s7o54n9pml.png" alt="Rust With Dependency Injection" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good news is that we already have &lt;strong&gt;use-traits&lt;/strong&gt;, and our components are decoupled. We can extract certain code into reusable modules.&lt;/p&gt;

&lt;p&gt;What’s missing for a &lt;strong&gt;true dependency injection system&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ApplicationContext&lt;/code&gt; still has too much knowledge about the components it uses.&lt;/li&gt;
&lt;li&gt;Some wiring and initialization steps are still &lt;strong&gt;manual&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our goal is to move the &lt;strong&gt;wiring into DI modules&lt;/strong&gt;, giving each component full control over how it is connected.&lt;/p&gt;

&lt;p&gt;Because we are still targeting &lt;strong&gt;compile-time injection&lt;/strong&gt;, we cannot rely on runtime reflection (like Java DI frameworks do). Instead, we will push this logic into Rust macros, allowing compile-time wiring while preserving zero-cost abstractions.&lt;/p&gt;

&lt;p&gt;The final code for this stage is here: &lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_no_init.rs" rel="noopener noreferrer"&gt;Rust DI Example — DI Without Manual Initialization&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_no_init.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_no_init.rs&lt;/a&gt;)&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Registering Components in &lt;code&gt;ApplicationContext&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In traditional DI, the application knows which modules it depends on (like Spring Data). But &lt;strong&gt;modules themselves should control which components they export&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In our previous example, &lt;code&gt;ApplicationContext&lt;/code&gt; was a struct, and registering a component meant adding a field manually. This ties the application to module internals. We need a way to &lt;strong&gt;add fields to &lt;code&gt;ApplicationContext&lt;/code&gt; automatically&lt;/strong&gt;, without putting module-specific code into the executable.&lt;/p&gt;

&lt;p&gt;We can achieve this using the &lt;code&gt;combine-structs&lt;/code&gt; crate, which provides macros to &lt;strong&gt;embed multiple structs into one&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://lib.rs/crates/combine-structs" rel="noopener noreferrer"&gt;https://lib.rs/crates/combine-structs&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each module defines an embeddable struct as a context extension. When imported, ApplicationContext automatically merges all fields from these extensions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1.1 Context Extension for PostgreSQL
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Fields)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;postgres_database_connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;Fields&lt;/code&gt; derive macro allows this struct to be merged into &lt;code&gt;ApplicationContext&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1.2 Context Extension for Controllers
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Fields)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ControllerContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;read_controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReadController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;write_controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WriteController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The controller module exports two controllers. More components can be added without touching the main executable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  1.3 Embedding Context Extensions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[combine_fields(PostgresDatabaseContextExtension,&lt;/span&gt; &lt;span class="nd"&gt;ControllerContextExtension)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;combine_fields&lt;/code&gt; macro merges all fields from the context extensions. &lt;code&gt;ApplicationContext&lt;/code&gt; now has all components automatically wired.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Providing Use-Traits
&lt;/h3&gt;

&lt;p&gt;Previously, wiring was done via use-traits. Now that &lt;code&gt;ApplicationContext&lt;/code&gt; doesn’t know which components exist, modules must &lt;strong&gt;export use-trait implementations via macros&lt;/strong&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  2.1 Macro for Database Connectivity
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_postgres_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;database_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.postgres_database_connection&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.2 Macro for Controllers
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_controller_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseReadController&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ReadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.read_controller&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseWriteController&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;WriteController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.write_controller&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.3 Injecting Components
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[combine_fields(PostgresDatabaseContextExtension,&lt;/span&gt; &lt;span class="nd"&gt;ControllerContextExtension)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;inject_postgres_impl!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;inject_controller_impl!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The executable only calls these macros. Components remain &lt;strong&gt;isolated from the main application&lt;/strong&gt;, and the wiring happens automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Intermediate Conclusion
&lt;/h3&gt;

&lt;p&gt;At this stage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No component code has been changed.&lt;/li&gt;
&lt;li&gt;Modules can add or remove components freely.&lt;/li&gt;
&lt;li&gt;Components are decoupled from each other and from the container.&lt;/li&gt;
&lt;li&gt;Wiring happens automatically through macros and use-traits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives us a &lt;strong&gt;bare-minimum dependency injection system&lt;/strong&gt;: application components are decoupled, wiring is automatic, and no single component needs full knowledge of the application.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Limitations
&lt;/h3&gt;

&lt;p&gt;Even though we now have a working DI mechanism, it &lt;strong&gt;isn’t fully production-ready&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initialization&lt;/strong&gt;: Components may require setup before wiring.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lifecycle Management&lt;/strong&gt;: Controlling initialization order, cleanup, or optional components can be challenging.&lt;/p&gt;

&lt;p&gt;Next, we will explore a Rust DI framework capable of &lt;strong&gt;automating component initialization and lifecycle management&lt;/strong&gt;, moving closer to a complete solution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Dependency Injection and Initialization Cycle in Rust
&lt;/h2&gt;

&lt;p&gt;So far, we have built a &lt;strong&gt;dependency injection (DI) container&lt;/strong&gt; where all components are stored as fields in &lt;code&gt;ApplicationContext&lt;/code&gt;. The next challenge is &lt;strong&gt;initializing these components&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmy9u90olzjj979u3bmuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmy9u90olzjj979u3bmuz.png" alt="Dependency Injection and Initialization Cycle in Rust" width="640" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enumerate the fields of &lt;code&gt;ApplicationContext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Identify which fields require initialization.&lt;/li&gt;
&lt;li&gt;Call an initialization method for each such component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we want everything to happen at &lt;strong&gt;compile time&lt;/strong&gt;, we need a macro to generate a Rust method that calls &lt;code&gt;init()&lt;/code&gt; on every tagged component &lt;strong&gt;without runtime loops or collections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I could not find an existing macro for this, so I implemented one myself. If you want the details, check the implementation here: &lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_macro/src/lib.rs" rel="noopener noreferrer"&gt;di_macro/src/lib.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_macro/src/lib.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_macro/src/lib.rs&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In this article, we will focus on &lt;strong&gt;how to use this macro&lt;/strong&gt;, not how it works internally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Macro Example: Enumerating Tagged Fields
&lt;/h2&gt;

&lt;p&gt;Full example code: &lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/struct_enumerator.rs" rel="noopener noreferrer"&gt;struct_enumerator.rs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/struct_enumerator.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/struct_enumerator.rs&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Define a Struct with Tagged Fields
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;FieldEnumerator,&lt;/span&gt; &lt;span class="nd"&gt;Default)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyStruct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[tag(init_listener)]&lt;/span&gt;
    &lt;span class="n"&gt;field_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nd"&gt;#[tag(init_listener)]&lt;/span&gt;
    &lt;span class="nd"&gt;#[tag(start_listener)]&lt;/span&gt;
    &lt;span class="n"&gt;field_1_2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="n"&gt;field_2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nd"&gt;#[tag(start_listener)]&lt;/span&gt;
    &lt;span class="n"&gt;field_3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FieldEnumerator&lt;/code&gt; is our custom derive macro.&lt;/li&gt;
&lt;li&gt;Fields can have &lt;strong&gt;one or more tags&lt;/strong&gt; (&lt;code&gt;init_listener&lt;/code&gt;, &lt;code&gt;start_listener&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Define a Callback Macro
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;my_callback&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$struct_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$field_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$listener_type:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"struct = {}, field = {}, type = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nd"&gt;stringify!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$struct_name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nd"&gt;stringify!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$field_name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nd"&gt;stringify!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$listener_type&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For every tagged field, the callback macro is called at compile time.&lt;/li&gt;
&lt;li&gt;Arguments passed: &lt;code&gt;struct_name&lt;/code&gt;, &lt;code&gt;field_name&lt;/code&gt;, and &lt;code&gt;listener_type&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Invoke the Field Enumerator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;my_struct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MyStruct&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_struct = {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_struct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;enumerate_tags_MyStruct_init_listener!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;enumerate_tags_MyStruct_start_listener!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;enumerate_tags_MyStruct_init_listener!&lt;/code&gt; and &lt;code&gt;enumerate_tags_MyStruct_start_listener!&lt;/code&gt; are &lt;strong&gt;generated automatically&lt;/strong&gt; by the &lt;code&gt;FieldEnumerator&lt;/code&gt; macro.&lt;/li&gt;
&lt;li&gt;The macro expands into a &lt;strong&gt;flat sequence of &lt;code&gt;println!()&lt;/code&gt;&lt;/strong&gt; calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Macro Example Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// enumerate_tags_MyStruct_init_listener!(my_callback);&lt;/span&gt;
    &lt;span class="c1"&gt;// my_callback!(MyStruct, field_1, init_listener)&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"struct = {}, field = {}, type = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyStruct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"field_1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"init_listener"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// my_callback!(MyStruct, field_1_2, init_listener)&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"struct = {}, field = {}, type = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyStruct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"field_1_2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"init_listener"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//enumerate_tags_MyStruct_start_listener!(my_callback)&lt;/span&gt;
    &lt;span class="c1"&gt;// my_callback!(MyStruct, field_1_2, start_listener)&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"struct = {}, field = {}, type = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyStruct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"field_1_2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"start_listener"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// my_callback!(MyStruct, field_3, start_listener)&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"struct = {}, field = {}, type = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyStruct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"field_3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"start_listener"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice: No vectors, arrays, loops, or runtime collections — &lt;strong&gt;everything happens at compile time&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rust Dependency Injection with Initialization
&lt;/h2&gt;

&lt;p&gt;We can now use the same macro to &lt;strong&gt;enumerate all fields in &lt;code&gt;ApplicationContext&lt;/code&gt; and initialize them&lt;/strong&gt;.&lt;br&gt;
Code reference: &lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_init.rs" rel="noopener noreferrer"&gt;di_init.rs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_init.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_init.rs&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;We introduce a &lt;strong&gt;Configuration component&lt;/strong&gt; to demonstrate how initialization can depend on runtime data.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Configuration Module
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;run_arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Fields,&lt;/span&gt; &lt;span class="nd"&gt;Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ConfigurationContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;UseConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration_mut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_configuration_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseConfiguration&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.configuration&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration_mut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.configuration&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the &lt;strong&gt;component struct&lt;/strong&gt; (&lt;code&gt;Configuration&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Define a &lt;strong&gt;context extension&lt;/strong&gt; for &lt;code&gt;ApplicationContext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Define a &lt;strong&gt;use-trait&lt;/strong&gt; (&lt;code&gt;UseConfiguration&lt;/code&gt;) for wiring.&lt;/li&gt;
&lt;li&gt;Provide a &lt;strong&gt;macro&lt;/strong&gt; to implement the trait on &lt;code&gt;ApplicationContext&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;Configuration&lt;/code&gt; is no longer zero-sized—it contains runtime data (&lt;code&gt;run_arguments&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  2. Database Connection Initialization
&lt;/h3&gt;
&lt;h4&gt;
  
  
  2.1 Update &lt;code&gt;PostgresDatabaseConnection&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;connection_string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Now contains &lt;strong&gt;runtime data&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Initialization depends on &lt;strong&gt;configuration&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2.2 Tag Component for Initialization
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Fields,&lt;/span&gt; &lt;span class="nd"&gt;ContextExtension)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[tag(init_listener)]&lt;/span&gt;
    &lt;span class="n"&gt;postgres_database_connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;init_listener&lt;/code&gt; signals that the component requires initialization.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2.3 Define &lt;code&gt;Initializable&lt;/code&gt; Trait
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Components implementing this trait can be initialized automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2.4 Implement Initialization
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UseConfiguration&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;UsePostgresDatabaseConnection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;PostgresDatabaseConnection&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Init sequence = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.configuration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.run_arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.postgres_database_connection_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.connection_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Postgres DB on {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.configuration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.run_arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Accesses ApplicationContext mutably for initialization of any of component.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;
  
  
  2.5 Prepare &lt;code&gt;ApplicationContext&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[combine_fields(&lt;/span&gt;
    &lt;span class="nd"&gt;ConfigurationContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;PostgresDatabaseContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;ControllerContextExtension&lt;/span&gt;
&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default,&lt;/span&gt; &lt;span class="nd"&gt;FieldEnumerator)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;inject_postgres_impl!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;inject_controller_impl!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;inject_configuration_impl!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;FieldEnumerator&lt;/code&gt; for tag enumeration.&lt;/li&gt;
&lt;li&gt;Configuration module bindings included.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;
  
  
  2.6 Initialization Sequence
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;call_init&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ApplicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;_closure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;init_callback&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$struct_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$field_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$listener_type:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;call_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;.&lt;span class="nv"&gt;$field_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;enumerate_tags_ApplicationContext_init_listener!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;call_init&lt;/code&gt; function&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This helper function takes a generic type &lt;code&gt;T&lt;/code&gt; that implements &lt;code&gt;Initializable&amp;lt;ApplicationContext&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It also takes a closure &lt;code&gt;_closure&lt;/code&gt; of type &lt;code&gt;Fn(ApplicationContext) -&amp;gt; T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The trick here: &lt;code&gt;the Rust compiler monomorphizes the closure&lt;/code&gt; to the actual type of the field passed in, so &lt;code&gt;T::init(ctx)&lt;/code&gt; is called with the concrete type.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;amp;&amp;amp;&lt;code&gt;init_callback!&lt;/code&gt; macro**

&lt;ul&gt;
&lt;li&gt;The macro expands for each field tagged with &lt;code&gt;init_listener&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It calls &lt;code&gt;call_init&lt;/code&gt; with the correct field from &lt;code&gt;self&lt;/code&gt;, ensuring the proper &lt;code&gt;Initializable&lt;/code&gt; implementation is invoked.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;enumerate_tags_ApplicationContext_init_listener! macro&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This macro iterates over all fields in &lt;code&gt;ApplicationContext&lt;/code&gt; that are marked with &lt;code&gt;#[init_listener]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For each field, it invokes &lt;code&gt;init_callback!&lt;/code&gt;, which triggers &lt;code&gt;Initializable::init&lt;/code&gt; for that specific component.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key Rust trick&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By using the &lt;code&gt;Fn&lt;/code&gt; trait and generics in &lt;code&gt;call_init&lt;/code&gt;, the compiler &lt;code&gt;resolves the actual type of the field at compile time&lt;/code&gt;.&lt;br&gt;
This avoids any runtime type checks and ensures &lt;code&gt;zero-cost initialization&lt;/code&gt; while keeping strong type safety.&lt;/p&gt;


&lt;h4&gt;
  
  
  2.7 Running the Application
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ApplicationContext&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.configuration_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.run_arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DB_URL=127.0.0.1:5555"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.read_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.write_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Sample Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Init sequence = DB_URL=127.0.0.1:5555
Reading from Postgres DB on DB_URL=127.0.0.1:5555: SELECT * FROM table WHERE id = 'argument'
Writing into Postgres DB on DB_URL=127.0.0.1:5555: UPDATE table SET value = 'new' WHERE id = 'argument'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;run_arguments&lt;/code&gt; successfully propagated into runtime data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Considerations
&lt;/h3&gt;

&lt;p&gt;In this demo, some structs now hold &lt;strong&gt;runtime data&lt;/strong&gt; — but this is intentional. It’s added to &lt;strong&gt;demonstrate initialization&lt;/strong&gt;, just like in real applications where components manage runtime state.&lt;/p&gt;

&lt;p&gt;The wiring mechanism itself remains &lt;strong&gt;zero-cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All bindings are resolved at compile time through &lt;strong&gt;monomorphization&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even with the initialization sequence broadcasting multiple &lt;code&gt;init&lt;/code&gt; calls, the compiler generates a &lt;strong&gt;flat sequence of calls&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No loops, no runtime collections, no dynamic dispatch — everything happens at compile time, efficiently.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This approach is now &lt;strong&gt;mature and production-ready&lt;/strong&gt; for wiring, decoupling, and initialization.&lt;/li&gt;
&lt;li&gt;Next steps can explore &lt;strong&gt;advanced topics&lt;/strong&gt;, such as polymorphism and more complex runtime behaviors.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Dependency Injection and Polymorphism
&lt;/h2&gt;

&lt;p&gt;This is the final example of the article and introduces what I would consider an &lt;strong&gt;advanced topic&lt;/strong&gt; for the core engine of any dependency injection framework: &lt;strong&gt;polymorphism&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds1qqjdet2h3qcuw1bfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds1qqjdet2h3qcuw1bfe.png" alt="Dependency Injection and Polymorphism" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many DI frameworks handle basic dependency wiring well. For example, &lt;strong&gt;Java Spring Boot&lt;/strong&gt; provides a very mature implementation. However, in many other DI implementations, one important capability is often missing — the ability to &lt;strong&gt;handle multiple implementations of the same abstraction&lt;/strong&gt; in a flexible and compile-time-safe way.&lt;/p&gt;

&lt;p&gt;Let’s extend our example with a new requirement.&lt;/p&gt;




&lt;h3&gt;
  
  
  New Requirement
&lt;/h3&gt;

&lt;p&gt;Our application should support &lt;strong&gt;multiple message brokers&lt;/strong&gt;, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After writing data to the database, the controller should &lt;strong&gt;publish a message to one or more brokers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The component &lt;strong&gt;does not know which brokers exist&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The container &lt;strong&gt;may contain multiple brokers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The DI framework must maintain this &lt;strong&gt;one-to-many relationship&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;one component should be able to call many broker implementations without knowing which ones exist.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make things even more interesting, we introduce the concept of &lt;strong&gt;profiles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each profile represents a &lt;strong&gt;different configuration of the application context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Profile1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL database&lt;/li&gt;
&lt;li&gt;Kafka broker&lt;/li&gt;
&lt;li&gt;RabbitMQ broker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Profile2&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oracle database&lt;/li&gt;
&lt;li&gt;RabbitMQ broker only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Complete example:&lt;br&gt;
&lt;a href="https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_polymorphism.rs" rel="noopener noreferrer"&gt;https://github.com/amidukr/rust-dependency-injection-example/blob/main/di_example/src/examples/di_polymorphism.rs&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Injection Macros and Profiles
&lt;/h3&gt;

&lt;p&gt;First, we slightly modify our &lt;strong&gt;injection macros&lt;/strong&gt; so they accept the application context type as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_configuration_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseConfiguration&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.configuration&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;configuration_mut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.configuration&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This change is necessary because:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The DI module does not know which &lt;strong&gt;profile&lt;/strong&gt; will be used.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each executable can choose a &lt;strong&gt;different application context profile&lt;/strong&gt;, and the macros must work with whichever profile is selected.&lt;br&gt;
Oracle Database Component&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Oracle Database Component
&lt;/h3&gt;

&lt;p&gt;Now we introduce a new database implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Fields,&lt;/span&gt; &lt;span class="nd"&gt;ContextExtension)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;OracleDatabaseContextExtension&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the injection macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_oracle_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Reading from Oracle DB: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;write_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Writing into Oracle DB {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UseDatabaseConnection&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;database_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we apply a small trick.&lt;/p&gt;

&lt;p&gt;Instead of defining a separate struct for the database connection, we &lt;strong&gt;implement the trait directly on the application context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach avoids additional boilerplate and works well when we know there will only be &lt;strong&gt;one database implementation per profile&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Defining Message Brokers
&lt;/h3&gt;

&lt;p&gt;Now we define the abstraction for message brokers.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.1 Broker Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;BrokerSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;send_to_broker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  3.2 RabbitMQ Broker
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default,&lt;/span&gt; &lt;span class="nd"&gt;Fields,&lt;/span&gt; &lt;span class="nd"&gt;ContextExtension)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;RabbitMqContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[tag(broker)]&lt;/span&gt;
    &lt;span class="n"&gt;rabbit_mq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RabbitMq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;RabbitMq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;BrokerSender&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;RabbitMq&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;send_to_broker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{} sent to RabbitMq"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the important detail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[tag(broker)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tag allows the DI framework to &lt;strong&gt;enumerate all brokers automatically&lt;/strong&gt; using the same mechanism we previously used for initialization.&lt;/p&gt;




&lt;h4&gt;
  
  
  3.3 Kafka Broker
&lt;/h4&gt;

&lt;p&gt;Kafka is implemented in exactly the same way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[allow(dead_code)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default,&lt;/span&gt; &lt;span class="nd"&gt;Fields,&lt;/span&gt; &lt;span class="nd"&gt;ContextExtension)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;KafkaContextExtension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[tag(broker)]&lt;/span&gt;
    &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Kafka&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Default)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Kafka&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;BrokerSender&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Kafka&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;send_to_broker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{} sent to Kafka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Publisher — Compile-Time Polymorphism&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now comes the most interesting part.&lt;/p&gt;

&lt;p&gt;We define a &lt;strong&gt;Publisher&lt;/strong&gt; component that sends messages to &lt;strong&gt;all available brokers&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Publisher&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Injection macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;inject_publisher_impl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Publisher&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;broker_callback&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$struct_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$field_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$listener_type:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;self&lt;/span&gt;.&lt;span class="nv"&gt;$field_name&lt;/span&gt;&lt;span class="nf"&gt;.send_to_broker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nd"&gt;enumerate_tags!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;broker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;broker_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;UsePublisher&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The publisher &lt;strong&gt;does not know which brokers exist&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, the &lt;strong&gt;FieldEnumerator macro generates code&lt;/strong&gt; that calls &lt;code&gt;send_to_broker&lt;/code&gt; for each tagged broker.&lt;/p&gt;

&lt;p&gt;This gives us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one-to-many relationship&lt;/li&gt;
&lt;li&gt;compile-time wiring&lt;/li&gt;
&lt;li&gt;no dynamic dispatch&lt;/li&gt;
&lt;li&gt;no runtime overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.1 Helper Macro for Tag Enumeration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;enumerate_tags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$tag:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$callback:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;paste!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;enumerate_tags_&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;$tag&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This macro simply dispatches to the &lt;strong&gt;procedural macro generated earlier&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Application Profiles
&lt;/h3&gt;

&lt;p&gt;Now we define two different application contexts.&lt;/p&gt;

&lt;h4&gt;
  
  
  5.1 Profile 1
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[combine_fields(&lt;/span&gt;
    &lt;span class="nd"&gt;ConfigurationContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;PostgresDatabaseContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;ControllerContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;PublisherExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;RabbitMqContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;KafkaContextExtension&lt;/span&gt;
&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default,&lt;/span&gt; &lt;span class="nd"&gt;FieldEnumerator)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Profile1 includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  5.2 Profile 2
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[combine_fields(&lt;/span&gt;
    &lt;span class="nd"&gt;ConfigurationContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;OracleDatabaseContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;ControllerContextExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;PublisherExtension,&lt;/span&gt;
    &lt;span class="nd"&gt;RabbitMqContextExtension&lt;/span&gt;
&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Default,&lt;/span&gt; &lt;span class="nd"&gt;FieldEnumerator)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Profile2 includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oracle database&lt;/li&gt;
&lt;li&gt;RabbitMQ broker&lt;/li&gt;
&lt;li&gt;no Kafka&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. Initialization Macro for Context
&lt;/h3&gt;

&lt;p&gt;We move the previously used initialization logic into a reusable macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;application_context&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;assert_send_sync&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Sync&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="nn"&gt;assert_send_sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;call_init&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;_closure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;init_callback&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$struct_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$field_name:ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$listener_type:ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;call_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;.&lt;span class="nv"&gt;$field_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nd"&gt;enumerate_tags!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init_listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. Wiring Profiles
&lt;/h3&gt;

&lt;h4&gt;
  
  
  7.1 Profile1
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;application_context!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;inject_postgres_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_controller_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_configuration_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_publisher_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_rabbit_mq_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_kafka_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  7.2 Profile2
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;application_context!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;inject_oracle_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_controller_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_configuration_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_publisher_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;inject_rabbit_mq_impl!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Running the Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_run&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Initializable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;UseConfiguration&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.configuration_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.run_arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DB_URL=127.0.0.1:5555"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.read_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="nf"&gt;.write_controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running Profile1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;do_run&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running Profile2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;do_run&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationProfile2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Running Profile1
Configuration = DB_URL=127.0.0.1:5555
PostgresDB connection init sequence = DB_URL=127.0.0.1:5555
Reading from Postgres DB...
Writing into Postgres DB...
WriteController 'argument' sent to RabbitMq
WriteController 'argument' sent to Kafka

Running Profile2
Configuration = DB_URL=127.0.0.1:5555
Reading from Oracle DB...
Writing into Oracle DB...
WriteController 'argument' sent to RabbitMq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Result
&lt;/h3&gt;

&lt;p&gt;With this approach we achieved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;compile-time polymorphism&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;one-to-many dependency injection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;profile-based application configuration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no dynamic dispatch&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no runtime container&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fully monomorphized wiring&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Everything is resolved at compile time while still supporting flexible application configurations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion: Can Rust Have Zero-Cost Dependency Injection?
&lt;/h2&gt;

&lt;p&gt;Throughout this article we explored whether &lt;strong&gt;Dependency Injection can exist in Rust without introducing runtime overhead&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Traditional DI frameworks in languages such as Java rely heavily on &lt;strong&gt;reflection, runtime containers, dynamic dispatch, and runtime graph construction&lt;/strong&gt;. These features make frameworks like Spring Boot extremely flexible, but they also introduce &lt;strong&gt;runtime complexity and performance costs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rust approaches the problem differently.&lt;/p&gt;

&lt;p&gt;Instead of relying on runtime containers, the examples in this article demonstrate how &lt;strong&gt;compile-time composition&lt;/strong&gt; can be used to build a dependency injection system. Using traits, generics, procedural macros, and compile-time code generation, we can construct an application context where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;component wiring happens at &lt;strong&gt;compile time&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;dependencies are resolved through &lt;strong&gt;traits and generics&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;initialization logic can be &lt;strong&gt;generated statically&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;polymorphism can be implemented &lt;strong&gt;without dynamic dispatch&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Rust performs &lt;strong&gt;monomorphization&lt;/strong&gt; during compilation, every dependency binding is resolved into &lt;strong&gt;concrete function calls&lt;/strong&gt;. This means the final binary contains no reflection, no dynamic lookup tables, and no runtime dependency container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In other words, dependency injection becomes a &lt;strong&gt;compile-time architectural pattern rather than a runtime framework&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We also demonstrated several important features typically expected from mature DI systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modular component composition through &lt;strong&gt;context extensions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;controlled &lt;strong&gt;initialization sequences&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;one-to-many polymorphism&lt;/strong&gt; for components such as brokers&lt;/li&gt;
&lt;li&gt;configurable &lt;strong&gt;application profiles&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;and all of this without introducing &lt;strong&gt;runtime cost or dynamic dispatch&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a system where &lt;strong&gt;flexibility and performance are not in conflict&lt;/strong&gt;.&lt;br&gt;
Rust’s type system and macro system allow us to design architectures that remain &lt;strong&gt;fully decoupled&lt;/strong&gt;, while still producing &lt;strong&gt;simple, predictable, zero-cost binaries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This raises an interesting conclusion.&lt;/p&gt;

&lt;p&gt;Rust may never have a DI framework that looks like Spring Boot — and it probably shouldn’t. But Rust &lt;strong&gt;does allow dependency injection to exist in a different form&lt;/strong&gt;, one that embraces the language’s philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;compile-time guarantees, explicit composition, and zero-cost abstractions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Future Directions
&lt;/h2&gt;

&lt;p&gt;The examples in this article intentionally keep the framework small in order to focus on the core ideas. However, a production-ready system would likely evolve further. For example, initialization often requires &lt;strong&gt;explicit ordering between components&lt;/strong&gt;, where some services must be initialized before others. The current example also contains a fair amount of &lt;strong&gt;boilerplate&lt;/strong&gt;, which could be significantly reduced with a more advanced procedural macro design. Heavier use of derive and attribute macros could also improve &lt;strong&gt;IDE code completion and developer ergonomics&lt;/strong&gt; while keeping the system fully type-safe.&lt;/p&gt;

&lt;p&gt;Beyond the core container mechanics, several practical features naturally follow from this model: improved &lt;strong&gt;testing support&lt;/strong&gt;, built-in mechanisms for &lt;strong&gt;mocking and stubbing components&lt;/strong&gt;, and the ability to &lt;strong&gt;override components in derived profiles&lt;/strong&gt; — a common requirement when building test environments or specialized deployments.&lt;/p&gt;

&lt;p&gt;Finally, dependency injection frameworks rarely exist in isolation. Systems such as Spring Boot succeeded not only because of their DI container, but because they provided a &lt;strong&gt;standard foundation for an ecosystem of reusable modules&lt;/strong&gt;. A similar approach in Rust could allow libraries to integrate around a shared compile-time DI model, enabling a broader ecosystem of interoperable components while preserving Rust’s philosophy of &lt;strong&gt;explicit composition and zero-cost abstractions&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Curiosity about AI technologies led me to use ChatGPT to help improve the clarity and flow of this article. All technical ideas, architectural decisions, and Rust code examples are entirely my own. I am not affiliated with OpenAI, and this mention of ChatGPT is not sponsored, promoted, or intended as advertising — it is simply a note of gratitude for the support it provided in refining my writing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>architecture</category>
      <category>programming</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
