1use crate::{async_io::AsyncInstrument, Error, Instrument, JobID};
2use std::{
3 io,
4 pin::Pin,
5 task::{Context, Poll},
6};
7use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
8
9pub struct InstrumentTokioAdapter {
19 instr: AsyncInstrument,
21 read_current: Option<JobID>,
22 write_current: Option<JobID>,
23 read_buf: Vec<u8>,
25 read_pos: usize,
26 write_buf: Vec<u8>,
28}
29
30impl TryFrom<Instrument> for InstrumentTokioAdapter {
31 type Error = Error;
32 fn try_from(value: Instrument) -> Result<Self, Self::Error> {
33 Ok(Self::new(AsyncInstrument::new(value)?))
34 }
35}
36
37impl From<AsyncInstrument> for InstrumentTokioAdapter {
38 fn from(value: AsyncInstrument) -> Self {
39 Self::new(value)
40 }
41}
42
43impl From<InstrumentTokioAdapter> for AsyncInstrument {
44 fn from(mut value: InstrumentTokioAdapter) -> Self {
45 value.cancel_in_flight();
46 let value = std::mem::ManuallyDrop::new(value);
47 let instr = unsafe { std::ptr::read(&value.instr) };
50 drop(unsafe { std::ptr::read(&value.read_buf) });
51 drop(unsafe { std::ptr::read(&value.write_buf) });
52 instr
53 }
54}
55
56impl From<InstrumentTokioAdapter> for Instrument {
57 fn from(value: InstrumentTokioAdapter) -> Self {
58 let async_instr: AsyncInstrument = value.into();
59 async_instr.into()
60 }
61}
62
63impl InstrumentTokioAdapter {
64 pub fn new(instr: AsyncInstrument) -> Self {
65 Self {
66 instr,
67 read_current: None,
68 write_current: None,
69 read_buf: Vec::new(),
70 read_pos: 0,
71 write_buf: Vec::new(),
72 }
73 }
74
75 fn map_vs_err(err: Error) -> io::Error {
76 io::Error::other(err)
77 }
78
79 fn cancel_in_flight(&mut self) {
80 if let Some(job_id) = self.read_current.take() {
81 self.instr.cancel_job(job_id);
82 }
83 if let Some(job_id) = self.write_current.take() {
84 self.instr.cancel_job(job_id);
85 }
86 }
87
88 fn deliver(&mut self, buf: &mut ReadBuf<'_>) {
90 let available = &self.read_buf[self.read_pos..];
91 let n = available.len().min(buf.remaining());
92 buf.put_slice(&available[..n]);
93 self.read_pos += n;
94 if self.read_pos == self.read_buf.len() {
95 self.read_buf.clear();
96 self.read_pos = 0;
97 }
98 }
99
100 fn poll_current_write(&mut self, cx: &Context<'_>) -> Poll<io::Result<()>> {
101 let Some(job_id) = self.write_current else {
102 return Poll::Ready(Ok(()));
103 };
104 match self.instr.poll_job(job_id, cx) {
105 Poll::Ready((result, mut buf)) => {
106 self.write_current = None;
107 let expected = buf.len();
108 buf.clear();
109 self.write_buf = buf;
110 let completion = result.map_err(|e| {
111 log::error!("tokio async write completion error: {}", e);
112 Self::map_vs_err(e)
113 })?;
114 if completion.count != expected {
117 let kind = if completion.count == 0 {
118 io::ErrorKind::WriteZero
119 } else if completion.count > expected {
120 io::ErrorKind::InvalidData
121 } else {
122 io::ErrorKind::Other
123 };
124 return Poll::Ready(Err(io::Error::new(
125 kind,
126 format!(
127 "VISA wrote {} of {expected} accepted bytes",
128 completion.count
129 ),
130 )));
131 }
132 Poll::Ready(Ok(()))
133 }
134 Poll::Pending => Poll::Pending,
135 }
136 }
137}
138
139impl Drop for InstrumentTokioAdapter {
140 fn drop(&mut self) {
141 self.cancel_in_flight();
142 }
143}
144
145impl AsyncRead for InstrumentTokioAdapter {
146 fn poll_read(
147 self: Pin<&mut Self>,
148 cx: &mut Context<'_>,
149 buf: &mut ReadBuf<'_>,
150 ) -> Poll<io::Result<()>> {
151 let me = self.get_mut();
152 if buf.remaining() == 0 {
153 return Poll::Ready(Ok(()));
154 }
155 if me.read_current.is_none() {
156 if me.read_pos < me.read_buf.len() {
158 me.deliver(buf);
159 return Poll::Ready(Ok(()));
160 }
161 let mut owned = std::mem::take(&mut me.read_buf);
162 owned.clear();
163 owned.resize(
164 crate::instrument::async_transfer_count(buf.remaining()) as usize,
165 0,
166 );
167 me.read_pos = 0;
168 match me.instr.start_read_id(owned, cx.waker()) {
169 Ok(job_id) => me.read_current = Some(job_id),
170 Err(e) => return Poll::Ready(Err(Self::map_vs_err(e))),
171 }
172 }
173 let job_id = me.read_current.expect("set immediately above");
174 match me.instr.poll_job(job_id, cx) {
175 Poll::Ready((Ok(c), mut owned)) => {
176 me.read_current = None;
177 owned.truncate(c.count.min(owned.len()));
178 me.read_buf = owned;
179 me.read_pos = 0;
180 me.deliver(buf);
181 Poll::Ready(Ok(()))
182 }
183 Poll::Ready((Err(e), mut owned)) => {
184 me.read_current = None;
185 owned.clear();
186 me.read_buf = owned;
187 me.read_pos = 0;
188 log::error!("tokio async read completion error: {}", e);
189 Poll::Ready(Err(Self::map_vs_err(e)))
190 }
191 Poll::Pending => Poll::Pending,
192 }
193 }
194}
195
196impl AsyncWrite for InstrumentTokioAdapter {
197 fn poll_write(
201 self: Pin<&mut Self>,
202 cx: &mut Context<'_>,
203 buf: &[u8],
204 ) -> Poll<io::Result<usize>> {
205 let me = self.get_mut();
206 match me.poll_current_write(cx) {
207 Poll::Pending => {
208 if !buf.is_empty() {
209 log::warn!(
210 "tokio write waiting for previous VISA job; {} input bytes not accepted yet",
211 buf.len()
212 );
213 }
214 return Poll::Pending;
215 }
216 Poll::Ready(result) => result?,
217 }
218 if buf.is_empty() {
219 return Poll::Ready(Ok(0));
220 }
221 let n = crate::instrument::async_transfer_count(buf.len()) as usize;
223 let mut owned = std::mem::take(&mut me.write_buf);
224 owned.clear();
225 owned.extend_from_slice(&buf[..n]);
226 match me.instr.start_write_id(owned, cx.waker()) {
227 Ok(job_id) => me.write_current = Some(job_id),
228 Err(e) => return Poll::Ready(Err(Self::map_vs_err(e))),
229 }
230 Poll::Ready(Ok(n))
231 }
232
233 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
234 use crate::flags::FlushMode;
235 let me = self.get_mut();
236 std::task::ready!(me.poll_current_write(cx))?;
238 me.instr
239 .instrument()
240 .visa_flush(FlushMode::WRITE_BUF | FlushMode::IO_OUT_BUF)
241 .map_err(Self::map_vs_err)?;
242 Poll::Ready(Ok(()))
243 }
244
245 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
247 self.poll_flush(cx)
248 }
249}