1use super::{note_sync_completion, AsyncInstrument, Completed};
4use crate::instrument::async_transfer_count;
5use crate::{
6 enums::status::{CompletionCode, ErrorCode},
7 JobID, Result,
8};
9use std::{
10 future::Future,
11 pin::Pin,
12 task::{Context, Poll},
13};
14
15const READ_CHUNK: usize = 4096;
17
18fn collect_chunk(
20 out: &mut Vec<u8>,
21 limit: Option<usize>,
22 Completed { count, completion }: Completed,
23 mut buf: Vec<u8>,
24) -> Result<bool> {
25 let count = count.min(buf.len());
26 if out.is_empty() {
27 buf.truncate(count);
28 *out = buf;
29 } else {
30 out.extend_from_slice(&buf[..count]);
31 }
32 if let Some(limit) = limit {
33 if out.len() == limit {
34 return Ok(true);
35 }
36 if count == 0 {
39 return Err(ErrorCode::ErrorIo.into());
40 }
41 return Ok(false);
42 }
43 Ok(completion != CompletionCode::SuccessMaxCnt)
45}
46
47#[must_use = "futures do nothing unless you `.await` or poll them"]
52pub struct AsyncRead<'a> {
53 ss: &'a AsyncInstrument,
54 limit: Option<usize>,
56 timeout: std::time::Duration,
57 out: Vec<u8>,
58 id: Option<JobID>,
59 prepared: bool,
60 done: bool,
61}
62
63impl<'a> AsyncRead<'a> {
64 pub(super) fn new(
65 ss: &'a AsyncInstrument,
66 limit: Option<usize>,
67 timeout: std::time::Duration,
68 ) -> Self {
69 Self {
70 ss,
71 limit,
72 timeout,
73 out: Vec::new(),
74 id: None,
75 prepared: false,
76 done: false,
77 }
78 }
79
80 fn chunk_len(&self) -> usize {
81 match self.limit {
82 Some(n) => async_transfer_count(n.saturating_sub(self.out.len())) as usize,
85 None => READ_CHUNK,
87 }
88 }
89
90 fn finish(&mut self) -> Poll<Result<Vec<u8>>> {
91 self.done = true;
92 Poll::Ready(Ok(std::mem::take(&mut self.out)))
93 }
94}
95
96impl Future for AsyncRead<'_> {
97 type Output = Result<Vec<u8>>;
98
99 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
100 let me = self.get_mut();
101 if me.done {
102 return Poll::Ready(Err(ErrorCode::ErrorInvJobId.into()));
104 }
105 if !me.prepared {
106 if let Err(e) = me.ss.prepare_read(me.timeout, me.limit.is_none()) {
109 me.done = true;
110 return Poll::Ready(Err(e));
111 }
112 me.prepared = true;
113 }
114 loop {
115 if me.limit == Some(me.out.len()) {
116 return me.finish();
117 }
118 if me.id.is_none() {
119 let mut buf = vec![0u8; me.chunk_len()];
120 match unsafe { me.ss.instr.visa_read_async(&mut buf) } {
121 Ok((job_id, completion)) => {
122 me.ss.callback().register(job_id, cx.waker(), buf);
125 note_sync_completion(completion, job_id);
126 me.id = Some(job_id);
127 }
128 Err(e) => {
129 me.done = true;
131 return Poll::Ready(Err(e));
132 }
133 }
134 }
135 let job_id = me.id.expect("set immediately above");
136 match me.ss.poll_job(job_id, cx) {
137 Poll::Pending => return Poll::Pending,
138 Poll::Ready((Err(e), _)) => {
139 me.id = None;
140 me.done = true;
141 return Poll::Ready(Err(e));
142 }
143 Poll::Ready((Ok(completed), buf)) => {
144 me.id = None;
145 match collect_chunk(&mut me.out, me.limit, completed, buf) {
146 Ok(true) => return me.finish(),
147 Ok(false) => {}
148 Err(e) => {
149 me.done = true;
150 return Poll::Ready(Err(e));
151 }
152 }
153 }
154 }
155 }
156 }
157}
158
159impl Drop for AsyncRead<'_> {
160 fn drop(&mut self) {
161 if let Some(job_id) = self.id.take() {
162 self.ss.cancel_job(job_id);
163 }
164 }
165}
166
167#[must_use = "futures do nothing unless you `.await` or poll them"]
171pub struct AsyncWrite<'a> {
172 ss: &'a AsyncInstrument,
173 buf: Option<Vec<u8>>,
174 id: Option<JobID>,
175 len: usize,
176 written: usize,
177 done: bool,
178}
179
180impl<'a> AsyncWrite<'a> {
181 pub(super) fn new(ss: &'a AsyncInstrument, buf: Vec<u8>) -> Self {
182 Self {
183 ss,
184 len: buf.len(),
185 written: 0,
186 buf: Some(buf),
187 id: None,
188 done: false,
189 }
190 }
191}
192
193impl Future for AsyncWrite<'_> {
194 type Output = Result<usize>;
195
196 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
197 let me = self.get_mut();
198 if me.done {
199 return Poll::Ready(Err(ErrorCode::ErrorInvJobId.into()));
200 }
201 loop {
202 if me.written == me.len {
203 me.done = true;
204 return Poll::Ready(Ok(me.written));
205 }
206 if me.id.is_none() {
207 let buf = me
208 .buf
209 .take()
210 .expect("buffer held until the transfer starts");
211 match unsafe { me.ss.instr.visa_write_async(&buf[me.written..]) } {
213 Ok((job_id, completion)) => {
214 me.ss.callback().register(job_id, cx.waker(), buf);
215 note_sync_completion(completion, job_id);
216 me.id = Some(job_id);
217 }
218 Err(e) => {
219 me.done = true;
220 return Poll::Ready(Err(e));
221 }
222 }
223 }
224 let job_id = me.id.expect("set immediately above");
225 let (result, buf) = std::task::ready!(me.ss.poll_job(job_id, cx));
226 me.id = None;
227 match result.and_then(|c| advance_write(&mut me.written, me.len, c.count)) {
228 Ok(true) => {
229 me.done = true;
230 return Poll::Ready(Ok(me.written));
231 }
232 Ok(false) => me.buf = Some(buf),
233 Err(e) => {
234 me.done = true;
235 return Poll::Ready(Err(e));
236 }
237 }
238 }
239 }
240}
241
242fn advance_write(written: &mut usize, len: usize, count: usize) -> Result<bool> {
244 let requested = async_transfer_count(len - *written) as usize;
245 if count > requested {
246 return Err(ErrorCode::ErrorIo.into());
247 }
248 *written += count;
249 Ok(count < requested || *written == len)
250}
251
252impl Drop for AsyncWrite<'_> {
253 fn drop(&mut self) {
254 if let Some(job_id) = self.id.take() {
255 self.ss.cancel_job(job_id);
256 }
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn transfer_counts_fit_visa() {
266 for len in [0, 1, 4096, u32::MAX as usize] {
267 assert_eq!(async_transfer_count(len) as usize, len);
268 }
269 }
270
271 #[cfg(target_pointer_width = "64")]
272 #[test]
273 fn oversized_write_advances_without_wrapping() {
274 let max = u32::MAX as usize;
275 assert_eq!(async_transfer_count(max + 1) as usize, max);
276 assert_eq!(async_transfer_count(usize::MAX) as usize, max);
277 let len = 2 * max + 17;
278 let mut written = 0;
279 assert!(!advance_write(&mut written, len, max).unwrap());
280 assert_eq!(written, max);
281 assert!(!advance_write(&mut written, len, max).unwrap());
282 assert_eq!(written, 2 * max);
283 assert!(advance_write(&mut written, len, 17).unwrap());
284 assert_eq!(written, len);
285
286 written = 0;
288 assert!(!advance_write(&mut written, max + 1, max).unwrap());
289 assert!(advance_write(&mut written, max + 1, 1).unwrap());
290 assert_eq!(written, max + 1);
291
292 written = max;
294 assert!(advance_write(&mut written, max + 17, 3).unwrap());
295 assert_eq!(written, max + 3);
296 }
297
298 #[test]
299 fn write_progress_preserves_short_counts_and_rejects_overruns() {
300 let mut written = 0;
301 assert!(advance_write(&mut written, 8, 3).unwrap());
302 assert_eq!(written, 3);
303 assert!(advance_write(&mut written, 8, 0).unwrap());
304 assert_eq!(written, 3);
305 assert_eq!(
306 advance_write(&mut written, 8, 6),
307 Err(ErrorCode::ErrorIo.into())
308 );
309 assert_eq!(written, 3);
310 }
311
312 #[test]
313 fn exact_read_continues_after_short_end() {
314 let mut out = Vec::new();
315 let first = Completed {
316 count: 3,
317 completion: CompletionCode::Success,
318 };
319 assert!(!collect_chunk(&mut out, Some(8), first, b"abc\0\0\0\0\0".to_vec()).unwrap());
320 assert_eq!(out, b"abc");
321 let last = Completed {
322 count: 5,
323 completion: CompletionCode::SuccessMaxCnt,
324 };
325 assert!(collect_chunk(&mut out, Some(8), last, b"defgh".to_vec()).unwrap());
326 assert_eq!(out, b"abcdefgh");
327 }
328
329 #[test]
330 fn exact_read_finishes_at_count_regardless_of_completion_code() {
331 for completion in [
332 CompletionCode::Success,
333 CompletionCode::SuccessMaxCnt,
334 CompletionCode::SuccessTermChar,
335 ] {
336 let mut out = Vec::new();
337 assert!(collect_chunk(
338 &mut out,
339 Some(3),
340 Completed {
341 count: 3,
342 completion
343 },
344 b"abc".to_vec()
345 )
346 .unwrap());
347 assert_eq!(out, b"abc");
348 }
349 }
350
351 #[test]
352 fn exact_read_errors_on_zero_progress() {
353 for mut out in [Vec::new(), b"abc".to_vec()] {
354 let completed = Completed {
355 count: 0,
356 completion: CompletionCode::Success,
357 };
358 assert_eq!(
359 collect_chunk(&mut out, Some(8), completed, vec![0; 8]),
360 Err(ErrorCode::ErrorIo.into())
361 );
362 }
363 }
364
365 #[test]
366 fn response_read_still_finishes_at_end() {
367 let mut out = Vec::new();
368 let completed = Completed {
369 count: 3,
370 completion: CompletionCode::Success,
371 };
372 assert!(collect_chunk(&mut out, None, completed, b"abc\0\0".to_vec()).unwrap());
373 assert_eq!(out, b"abc");
374 }
375
376 #[test]
377 fn response_read_continues_after_full_chunk() {
378 let mut out = Vec::new();
379 let completed = Completed {
380 count: 3,
381 completion: CompletionCode::SuccessMaxCnt,
382 };
383 assert!(!collect_chunk(&mut out, None, completed, b"abc".to_vec()).unwrap());
384 assert_eq!(out, b"abc");
385 }
386}