xwt_tests/tests/
tokio_io_read_partial_buf.rs1use std::task::Poll;
21
22use tokio::io::AsyncRead;
23use xwt_core::prelude::*;
24
25const SENTINEL: u8 = 0xAA;
28
29#[derive(Debug, thiserror::Error)]
30pub enum Error<Endpoint>
31where
32 Endpoint: xwt_core::endpoint::Connect + std::fmt::Debug,
33 Endpoint::Connecting: std::fmt::Debug,
34 ConnectSessionFor<Endpoint>: xwt_core::session::stream::OpenBi + std::fmt::Debug,
35{
36 #[error("connect: {0}")]
37 Connect(#[source] xwt_error::Connect<Endpoint>),
38 #[error("open: {0}")]
39 Open(#[source] xwt_error::OpenBi<ConnectSessionFor<Endpoint>>),
40 #[error("write: {0}")]
41 Write(#[source] std::io::Error),
42 #[error("read: {0}")]
43 Read(#[source] std::io::Error),
44 #[error("no response")]
45 NoResponse,
46 #[error("poll_read with a fully-filled buffer returned `Poll::Pending` instead of completing immediately")]
47 FullBufPending,
48 #[error("poll_read wrote outside of the unfilled region: {actual:?}")]
49 ClobberedBuf { actual: Vec<u8> },
50 #[error("bad data: expected {expected:?}, got {actual:?}")]
51 BadData { expected: Vec<u8>, actual: Vec<u8> },
52}
53
54pub async fn run<Endpoint>(endpoint: Endpoint, url: &str) -> Result<(), Error<Endpoint>>
55where
56 Endpoint: xwt_core::endpoint::Connect + std::fmt::Debug,
57 Endpoint::Connecting: std::fmt::Debug,
58 ConnectSessionFor<Endpoint>: xwt_core::session::stream::OpenBi + std::fmt::Debug,
59 SendStreamFor<ConnectSessionFor<Endpoint>>: tokio::io::AsyncWrite,
60 RecvStreamFor<ConnectSessionFor<Endpoint>>: tokio::io::AsyncRead,
61{
62 let session = crate::utils::connect(&endpoint, url)
63 .await
64 .map_err(Error::Connect)?;
65
66 let (send_stream, recv_stream) = crate::utils::open_bi(&session).await.map_err(Error::Open)?;
67
68 tokio::pin!(send_stream);
69 tokio::pin!(recv_stream);
70
71 let payload = b"ABCD";
74 write_all(&mut send_stream, payload).await?;
75 read_exact_and_verify(recv_stream.as_mut(), &payload[..2]).await?;
76
77 let mut array = [SENTINEL; 4];
81 let mut read_buf = tokio::io::ReadBuf::new(&mut array);
82 let filled = read_buf.capacity();
83 read_buf.set_filled(filled);
84 let poll =
85 std::future::poll_fn(|cx| Poll::Ready(recv_stream.as_mut().poll_read(cx, &mut read_buf)))
86 .await;
87 match poll {
88 Poll::Ready(Ok(())) => {}
89 Poll::Ready(Err(error)) => return Err(Error::Read(error)),
90 Poll::Pending => return Err(Error::FullBufPending),
91 }
92 if read_buf.filled() != [SENTINEL; 4] {
93 return Err(Error::ClobberedBuf {
94 actual: read_buf.filled().to_vec(),
95 });
96 }
97
98 read_exact_and_verify(recv_stream.as_mut(), &payload[2..]).await?;
100
101 let payload = b"EFGHIJKL";
104 write_all(&mut send_stream, payload).await?;
105
106 let mut array = [SENTINEL; 8];
107 let mut read_buf = tokio::io::ReadBuf::new(&mut array);
108 read_buf.set_filled(5);
109 let read = std::future::poll_fn(|cx| recv_stream.as_mut().poll_read(cx, &mut read_buf))
110 .await
111 .map(|()| read_buf.filled().len() - 5)
112 .map_err(Error::Read)?;
113 if read == 0 {
114 return Err(Error::NoResponse);
115 }
116 if read_buf.filled()[..5] != [SENTINEL; 5] {
117 return Err(Error::ClobberedBuf {
118 actual: read_buf.filled().to_vec(),
119 });
120 }
121 if read_buf.filled()[5..] != payload[..read] {
122 return Err(Error::BadData {
123 expected: payload[..read].to_vec(),
124 actual: read_buf.filled()[5..].to_vec(),
125 });
126 }
127
128 read_exact_and_verify(recv_stream.as_mut(), &payload[read..]).await?;
132
133 Ok(())
134}
135
136async fn write_all<Endpoint, S>(
138 send_stream: &mut S,
139 mut to_write: &[u8],
140) -> Result<(), Error<Endpoint>>
141where
142 Endpoint: xwt_core::endpoint::Connect + std::fmt::Debug,
143 Endpoint::Connecting: std::fmt::Debug,
144 ConnectSessionFor<Endpoint>: xwt_core::session::stream::OpenBi + std::fmt::Debug,
145 S: tokio::io::AsyncWrite + Unpin,
146{
147 loop {
148 let written = tokio::io::AsyncWriteExt::write(send_stream, to_write)
149 .await
150 .map_err(Error::Write)?;
151 to_write = &to_write[written..];
152 if to_write.is_empty() {
153 return Ok(());
154 }
155 }
156}
157
158async fn read_exact_and_verify<Endpoint, S>(
161 mut recv_stream: std::pin::Pin<&mut S>,
162 expected: &[u8],
163) -> Result<(), Error<Endpoint>>
164where
165 Endpoint: xwt_core::endpoint::Connect + std::fmt::Debug,
166 Endpoint::Connecting: std::fmt::Debug,
167 ConnectSessionFor<Endpoint>: xwt_core::session::stream::OpenBi + std::fmt::Debug,
168 S: tokio::io::AsyncRead,
169{
170 let mut received = vec![0u8; expected.len()];
171 let mut filled = 0;
172 while filled < expected.len() {
173 let mut read_buf = tokio::io::ReadBuf::new(&mut received[filled..]);
174 std::future::poll_fn(|cx| recv_stream.as_mut().poll_read(cx, &mut read_buf))
175 .await
176 .map_err(Error::Read)?;
177 let read = read_buf.filled().len();
178 if read == 0 {
179 return Err(Error::NoResponse);
180 }
181 filled += read;
182 }
183
184 if received != expected {
185 return Err(Error::BadData {
186 expected: expected.to_vec(),
187 actual: received,
188 });
189 }
190
191 Ok(())
192}