use crate::{Transport, TransportError, TransportFut};
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use std::{any::TypeId, fmt};
use tower::Service;
#[expect(unnameable_types)]
mod private {
pub trait Sealed {}
impl<T: super::Transport + Clone> Sealed for T {}
}
pub trait IntoBoxTransport: Transport + Clone + private::Sealed {
fn into_box_transport(self) -> BoxTransport;
}
impl<T: Transport + Clone> IntoBoxTransport for T {
fn into_box_transport(self) -> BoxTransport {
if TypeId::of::<T>() == TypeId::of::<BoxTransport>() {
let this = std::mem::ManuallyDrop::new(self);
return unsafe { std::mem::transmute_copy(&this) };
}
BoxTransport { inner: Box::new(self) }
}
}
pub struct BoxTransport {
inner: Box<dyn CloneTransport>,
}
impl BoxTransport {
#[inline]
pub fn new<T: IntoBoxTransport>(transport: T) -> Self {
transport.into_box_transport()
}
#[inline]
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() }
}
}
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,
{
#[inline]
fn clone_box(&self) -> Box<dyn CloneTransport + Send + Sync> {
Box::new(self.clone())
}
#[inline]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl Service<RequestPacket> for BoxTransport {
type Response = ResponsePacket;
type Error = TransportError;
type Future = TransportFut<'static>;
#[inline]
fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
#[inline]
fn call(&mut self, req: RequestPacket) -> Self::Future {
self.inner.call(req)
}
}
#[cfg(test)]
mod test {
use super::*;
#[derive(Clone)]
struct DummyTransport<T>(T);
impl<T> Service<RequestPacket> for DummyTransport<T> {
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>> {
unimplemented!()
}
fn call(&mut self, _req: RequestPacket) -> Self::Future {
unimplemented!()
}
}
const fn _compile_check() {
const fn inner<T>()
where
T: Transport + CloneTransport + Send + Sync + Clone + IntoBoxTransport + 'static,
{
}
inner::<BoxTransport>();
}
#[test]
fn no_reboxing() {
let id = TypeId::of::<DummyTransport<()>>();
no_reboxing_(DummyTransport(()), id);
no_reboxing_(BoxTransport::new(DummyTransport(())), id);
let wrap = String::from("hello");
let id = TypeId::of::<DummyTransport<String>>();
no_reboxing_(DummyTransport(wrap.clone()), id);
no_reboxing_(BoxTransport::new(DummyTransport(wrap)), id);
}
fn no_reboxing_<T: IntoBoxTransport>(t: T, id: TypeId) {
eprintln!("{}", std::any::type_name::<T>());
let t1 = BoxTransport::new(t);
let t1p = std::ptr::addr_of!(*t1.inner);
let t1id = t1.as_any().type_id();
let t2 = BoxTransport::new(t1);
let t2p = std::ptr::addr_of!(*t2.inner);
let t2id = t2.as_any().type_id();
assert_eq!(t1id, id);
assert_eq!(t1id, t2id);
assert!(std::ptr::eq(t1p, t2p));
}
}