alloy_transport/
boxed.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::{Transport, TransportError, TransportFut};
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use std::fmt;
use tower::Service;

/// A boxed, Clone-able [`Transport`] trait object.
///
/// This type allows RPC clients to use a type-erased transport. It is
/// [`Clone`] and [`Send`] + [`Sync`], and implements [`Transport`]. This
/// allows for complex behavior abstracting across several different clients
/// with different transport types.
///
/// Most higher-level types will be generic over `T: Transport = BoxTransport`.
/// This allows parameterization with a concrete type, while hiding this
/// complexity from the library consumer.
///
/// [`RpcClient`]: crate::client::RpcClient
#[repr(transparent)]
pub struct BoxTransport {
    inner: Box<dyn CloneTransport + Send + Sync>,
}

impl BoxTransport {
    /// Instantiate a new box transport from a suitable transport.
    pub fn new<T: Transport + Clone + Send + Sync>(inner: T) -> Self {
        Self { inner: Box::new(inner) }
    }

    /// Returns a reference to the inner transport.
    pub fn as_any(&self) -> &dyn std::any::Any {
        self.inner.as_any()
    }
}

impl fmt::Debug for BoxTransport {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BoxTransport").finish_non_exhaustive()
    }
}

impl Clone for BoxTransport {
    fn clone(&self) -> Self {
        Self { inner: self.inner.clone_box() }
    }
}

/// Helper trait for constructing [`BoxTransport`].
trait CloneTransport: Transport + std::any::Any {
    fn clone_box(&self) -> Box<dyn CloneTransport + Send + Sync>;
    fn as_any(&self) -> &dyn std::any::Any;
}

impl<T> CloneTransport for T
where
    T: Transport + Clone + Send + Sync,
{
    fn clone_box(&self) -> Box<dyn CloneTransport + Send + Sync> {
        Box::new(self.clone())
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

impl Service<RequestPacket> for BoxTransport {
    type Response = ResponsePacket;

    type Error = TransportError;

    type Future = TransportFut<'static>;

    fn poll_ready(
        &mut self,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, req: RequestPacket) -> Self::Future {
        self.inner.call(req)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    // checks trait + send + sync + 'static
    fn __compile_check() {
        fn inner<T: CloneTransport>(_: Option<T>) {}
        fn inner_2<T: Transport>(_: Option<T>) {}
        inner::<BoxTransport>(None);
        inner::<BoxTransport>(None);
    }
}