use std::any::Any;
use tokio::io::{AsyncRead, AsyncWrite};
pub trait Connection: Any + AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
}
impl<T> Connection for T
where
T: Any + AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
self
}
}
pub type BoxedConnection = Box<dyn Connection + Send + Sync>;
impl dyn Connection + Send + Sync {
pub fn downcast<T: Any + Send + Sync + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if (*self).as_any().is::<T>() {
let boxed_any = Connection::into_any(self);
Ok(boxed_any.downcast::<T>().unwrap())
} else {
Err(self)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::test]
async fn test_downcast_success_and_failure() {
let (mut a, b) = tokio::io::duplex(64);
let boxed: BoxedConnection = Box::new(b);
let res = boxed.downcast::<tokio::io::DuplexStream>();
assert!(res.is_ok());
let mut peer: Box<tokio::io::DuplexStream> = res.ok().unwrap();
let (_a2, b2) = tokio::io::duplex(32);
let boxed2: BoxedConnection = Box::new(b2);
let err = boxed2
.downcast::<tokio::net::TcpStream>()
.expect_err("expected Err on mismatch");
peer.write_all(b"ping").await.unwrap();
let mut buf = [0u8; 4];
a.read_exact(&mut buf).await.unwrap();
assert_eq!(&buf, b"ping");
let _ = err; }
}