use crate::Result;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use std::time::Duration;
pub async fn discard<S>(stream: S, d: Duration) -> Result<()>
where
S: AsyncRead + AsyncWrite + Unpin,
{
let (mut r, mut w) = tokio::io::split(stream);
let result = tokio::time::timeout(d, async move {
tokio::io::copy(&mut r, &mut tokio::io::sink()).await
})
.await;
if let Ok(r) = result {
r.map(|_| ()).map_err(|e| e.into())
} else {
w.shutdown().await.map_err(|e| e.into())
}
}
#[cfg(test)]
mod test {
use tokio::time::Instant;
use super::*;
#[tokio::test]
async fn discard_and_close_after_delay() {
let (mut c, s) = tokio::io::duplex(1024);
let start = Instant::now();
let d = Duration::from_secs(3);
let expected_end = start + d;
let discard_fut = discard(s, d);
tokio::spawn(async move {
const MSG: &str = "abcdefghijklmnopqrstuvwxyz";
loop {
if let Err(e) = c.write(MSG.as_bytes()).await {
assert!(Instant::now() > expected_end);
println!("closed with error {e}");
break;
}
}
});
discard_fut.await.unwrap();
assert!(Instant::now() > expected_end);
}
}