alloy_provider/provider/eth_call/
call_many.rs1use std::{marker::PhantomData, sync::Arc, task::Poll};
2
3use alloy_eips::BlockId;
4use alloy_json_rpc::RpcRecv;
5use alloy_network::Network;
6use alloy_rpc_types_eth::{state::StateOverride, Bundle, StateContext, TransactionIndex};
7use alloy_transport::TransportResult;
8use futures::{future, FutureExt};
9
10use crate::ProviderCall;
11
12use super::{Caller, EthCallManyParams};
13
14#[derive(Clone)]
16pub struct EthCallMany<'req, N, Resp: RpcRecv, Output = Resp, Map = fn(Resp) -> Output>
17where
18 N: Network,
19 Resp: RpcRecv,
20 Map: Fn(Resp) -> Output,
21{
22 caller: Arc<dyn Caller<N, Resp>>,
23 params: EthCallManyParams<'req>,
24 map: Map,
25 _pd: PhantomData<fn() -> (Resp, Output)>,
26}
27
28impl<N, Resp, Output, Map> std::fmt::Debug for EthCallMany<'_, N, Resp, Output, Map>
29where
30 N: Network,
31 Resp: RpcRecv,
32 Map: Fn(Resp) -> Output,
33{
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.debug_struct("EthCallMany")
36 .field("params", &self.params)
37 .field("method", &"eth_callMany")
38 .finish()
39 }
40}
41
42impl<'req, N, Resp> EthCallMany<'req, N, Resp>
43where
44 N: Network,
45 Resp: RpcRecv,
46{
47 pub fn new(caller: impl Caller<N, Resp> + 'static, bundles: &'req Vec<Bundle>) -> Self {
49 Self {
50 caller: Arc::new(caller),
51 params: EthCallManyParams::new(bundles),
52 map: std::convert::identity,
53 _pd: PhantomData,
54 }
55 }
56}
57
58impl<'req, N, Resp, Output, Map> EthCallMany<'req, N, Resp, Output, Map>
59where
60 N: Network,
61 Resp: RpcRecv,
62 Map: Fn(Resp) -> Output,
63{
64 pub fn map<NewOutput, NewMap>(
66 self,
67 map: NewMap,
68 ) -> EthCallMany<'req, N, Resp, NewOutput, NewMap>
69 where
70 NewMap: Fn(Resp) -> NewOutput,
71 {
72 EthCallMany { caller: self.caller, params: self.params, map, _pd: PhantomData }
73 }
74
75 pub fn block(mut self, block: BlockId) -> Self {
77 self.params = self.params.with_block(block);
78 self
79 }
80
81 pub fn transaction_index(mut self, tx_index: TransactionIndex) -> Self {
83 self.params = self.params.with_transaction_index(tx_index);
84 self
85 }
86
87 pub fn context(mut self, context: &'req StateContext) -> Self {
89 self.params = self.params.with_context(*context);
90 self
91 }
92
93 pub fn overrides(mut self, overrides: &'req StateOverride) -> Self {
95 self.params = self.params.with_overrides(overrides);
96 self
97 }
98
99 pub fn extend_bundles(mut self, bundles: &'req [Bundle]) -> Self {
101 self.params.bundles_mut().extend_from_slice(bundles);
102 self
103 }
104}
105
106impl<'req, N, Resp, Output, Map> std::future::IntoFuture for EthCallMany<'req, N, Resp, Output, Map>
107where
108 N: Network,
109 Resp: RpcRecv,
110 Map: Fn(Resp) -> Output,
111{
112 type Output = TransportResult<Output>;
113
114 type IntoFuture = CallManyFut<'req, N, Resp, Output, Map>;
115
116 fn into_future(self) -> Self::IntoFuture {
117 CallManyFut {
118 inner: CallManyInnerFut::Preparing {
119 caller: self.caller,
120 params: self.params,
121 map: self.map,
122 },
123 }
124 }
125}
126
127#[derive(Debug)]
129#[doc(hidden)] #[allow(unnameable_types)]
131#[pin_project::pin_project]
132pub struct CallManyFut<'req, N: Network, Resp: RpcRecv, Output, Map: Fn(Resp) -> Output> {
133 inner: CallManyInnerFut<'req, N, Resp, Output, Map>,
134}
135
136impl<N, Resp, Output, Map> CallManyFut<'_, N, Resp, Output, Map>
137where
138 N: Network,
139 Resp: RpcRecv,
140 Map: Fn(Resp) -> Output,
141{
142 const fn is_preparing(&self) -> bool {
143 matches!(self.inner, CallManyInnerFut::Preparing { .. })
144 }
145
146 const fn is_running(&self) -> bool {
147 matches!(self.inner, CallManyInnerFut::Running { .. })
148 }
149
150 fn poll_preparing(&mut self, cx: &mut std::task::Context<'_>) -> Poll<TransportResult<Output>> {
151 let CallManyInnerFut::Preparing { caller, params, map } =
152 std::mem::replace(&mut self.inner, CallManyInnerFut::Polling)
153 else {
154 unreachable!("bad state");
155 };
156
157 let fut = caller.call_many(params)?;
158 self.inner = CallManyInnerFut::Running { fut, map };
159 self.poll_running(cx)
160 }
161
162 fn poll_running(&mut self, cx: &mut std::task::Context<'_>) -> Poll<TransportResult<Output>> {
163 let CallManyInnerFut::Running { ref mut fut, ref map } = self.inner else {
164 unreachable!("bad state");
165 };
166
167 fut.poll_unpin(cx).map(|res| res.map(map))
168 }
169}
170
171impl<N, Resp, Output, Map> future::Future for CallManyFut<'_, N, Resp, Output, Map>
172where
173 N: Network,
174 Resp: RpcRecv,
175 Map: Fn(Resp) -> Output,
176{
177 type Output = TransportResult<Output>;
178
179 fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
180 let this = self.get_mut();
181
182 if this.is_preparing() {
183 this.poll_preparing(cx)
184 } else if this.is_running() {
185 this.poll_running(cx)
186 } else {
187 panic!("bad state");
188 }
189 }
190}
191
192enum CallManyInnerFut<'req, N: Network, Resp: RpcRecv, Output, Map: Fn(Resp) -> Output> {
193 Preparing { caller: Arc<dyn Caller<N, Resp>>, params: EthCallManyParams<'req>, map: Map },
194 Running { fut: ProviderCall<EthCallManyParams<'static>, Resp>, map: Map },
195 Polling,
196}
197
198impl<N, Resp, Output, Map> std::fmt::Debug for CallManyInnerFut<'_, N, Resp, Output, Map>
199where
200 N: Network,
201 Resp: RpcRecv,
202 Map: Fn(Resp) -> Output,
203{
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 match self {
206 CallManyInnerFut::Preparing { params, .. } => {
207 f.debug_tuple("Preparing").field(¶ms).finish()
208 }
209 CallManyInnerFut::Running { .. } => f.debug_tuple("Running").finish(),
210 CallManyInnerFut::Polling => f.debug_tuple("Polling").finish(),
211 }
212 }
213}