Skip to main content

moonpool_core/
providers.rs

1//! Provider bundle trait for simplified type parameters.
2//!
3//! This module provides a unified [`Providers`] trait that bundles all five
4//! provider types into a single type parameter, eliminating type parameter
5//! explosion in downstream code.
6//!
7//! ## Motivation
8//!
9//! Without bundling, code must carry five separate type parameters:
10//!
11//! ```text
12//! struct MyStruct<N, T, TP, R, S>
13//! where
14//!     N: NetworkProvider,
15//!     T: TimeProvider,
16//!     TP: TaskProvider,
17//!     R: RandomProvider,
18//!     S: StorageProvider,
19//! ```
20//!
21//! With bundling, this simplifies to:
22//!
23//! ```text
24//! struct MyStruct<P: Providers>
25//! ```
26//!
27//! ## Usage
28//!
29//! ```rust,ignore
30//! use moonpool_core::{Providers, TokioProviders};
31//!
32//! let providers = TokioProviders::new();
33//! let time_now = providers.time().now();
34//! ```
35
36use crate::{NetworkProvider, RandomProvider, StorageProvider, TaskProvider, TimeProvider};
37#[cfg(feature = "tokio-providers")]
38use crate::{
39    TokioNetworkProvider, TokioRandomProvider, TokioStorageProvider, TokioTaskProvider,
40    TokioTimeProvider,
41};
42
43/// Implement [`Providers`] for a struct whose fields are named
44/// `network`, `time`, `task`, `random`, `storage` — the five canonical
45/// provider slots.
46///
47/// Expands to the trait impl plus the five trivial getter forwards. The
48/// type of each slot is specified once in the macro invocation, so the
49/// implementing struct does not have to repeat the field-to-type mapping
50/// in the trait body.
51#[doc(hidden)]
52#[macro_export]
53macro_rules! impl_providers_bundle {
54    (
55        $struct:ty {
56            network: $network_ty:ty,
57            time: $time_ty:ty,
58            task: $task_ty:ty,
59            random: $random_ty:ty,
60            storage: $storage_ty:ty $(,)?
61        }
62    ) => {
63        impl $crate::Providers for $struct {
64            type Network = $network_ty;
65            type Time = $time_ty;
66            type Task = $task_ty;
67            type Random = $random_ty;
68            type Storage = $storage_ty;
69
70            fn network(&self) -> &Self::Network {
71                &self.network
72            }
73
74            fn time(&self) -> &Self::Time {
75                &self.time
76            }
77
78            fn task(&self) -> &Self::Task {
79                &self.task
80            }
81
82            fn random(&self) -> &Self::Random {
83                &self.random
84            }
85
86            fn storage(&self) -> &Self::Storage {
87                &self.storage
88            }
89        }
90    };
91}
92
93/// Bundle of all provider types for a runtime environment.
94///
95/// This trait consolidates the five provider types ([`NetworkProvider`],
96/// [`TimeProvider`], [`TaskProvider`], [`RandomProvider`], [`StorageProvider`])
97/// into a single bundle, reducing type parameter explosion and repetitive
98/// where clauses.
99///
100/// ## Implementations
101///
102/// - [`TokioProviders`]: Production providers using real Tokio runtime
103/// - `SimProviders` (in moonpool-sim): Simulation providers for deterministic testing
104///
105/// ## Design
106///
107/// The trait uses associated types to preserve type information at compile time
108/// without runtime dispatch. Accessor methods provide convenient access to
109/// individual providers while maintaining the bundle.
110pub trait Providers: Clone + Send + Sync + 'static {
111    /// Network provider type for TCP connections and listeners.
112    type Network: NetworkProvider;
113
114    /// Time provider type for sleep, timeout, and time queries.
115    type Time: TimeProvider;
116
117    /// Task provider type for spawning local tasks.
118    type Task: TaskProvider;
119
120    /// Random provider type for deterministic or real randomness.
121    type Random: RandomProvider;
122
123    /// Storage provider type for file I/O operations.
124    type Storage: StorageProvider;
125
126    /// Get the network provider instance.
127    fn network(&self) -> &Self::Network;
128
129    /// Get the time provider instance.
130    fn time(&self) -> &Self::Time;
131
132    /// Get the task provider instance.
133    fn task(&self) -> &Self::Task;
134
135    /// Get the random provider instance.
136    fn random(&self) -> &Self::Random;
137
138    /// Get the storage provider instance.
139    fn storage(&self) -> &Self::Storage;
140}
141
142/// Production providers using Tokio runtime.
143///
144/// This struct bundles all five Tokio-based providers into a single
145/// instance that implements [`Providers`].
146///
147/// ## Example
148///
149/// ```rust,ignore
150/// use moonpool_core::{Providers, TokioProviders};
151///
152/// let providers = TokioProviders::new();
153///
154/// // Access individual providers
155/// let network = providers.network();
156/// let time = providers.time();
157/// let task = providers.task();
158/// let random = providers.random();
159/// ```
160#[cfg(feature = "tokio-providers")]
161#[derive(Clone)]
162pub struct TokioProviders {
163    network: TokioNetworkProvider,
164    time: TokioTimeProvider,
165    task: TokioTaskProvider,
166    random: TokioRandomProvider,
167    storage: TokioStorageProvider,
168}
169
170#[cfg(feature = "tokio-providers")]
171impl TokioProviders {
172    /// Create a new production providers bundle.
173    ///
174    /// Initializes all five Tokio-based providers with their default
175    /// configurations.
176    #[must_use]
177    pub fn new() -> Self {
178        Self {
179            network: TokioNetworkProvider::new(),
180            time: TokioTimeProvider::new(),
181            task: TokioTaskProvider,
182            random: TokioRandomProvider::new(),
183            storage: TokioStorageProvider::new(),
184        }
185    }
186}
187
188#[cfg(feature = "tokio-providers")]
189impl Default for TokioProviders {
190    fn default() -> Self {
191        Self::new()
192    }
193}
194
195#[cfg(feature = "tokio-providers")]
196impl_providers_bundle!(TokioProviders {
197    network: TokioNetworkProvider,
198    time: TokioTimeProvider,
199    task: TokioTaskProvider,
200    random: TokioRandomProvider,
201    storage: TokioStorageProvider,
202});