Skip to main content

instrument_core/
transport.rs

1use crate::address::InterfaceKind;
2use crate::connect::ConnectOptions;
3use crate::error::{Error, Result, TransportError};
4use std::time::Duration;
5
6/// Optional pre-SCPI identity hints from the transport backend.
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
8pub struct TransportIdentity {
9    pub manufacturer: Option<String>,
10    pub model: Option<String>,
11    pub serial: Option<String>,
12    pub interface: InterfaceKind,
13    pub manf_id: Option<u32>,
14    pub model_code: Option<u32>,
15}
16
17/// Swappable byte-level transport for instrument I/O.
18pub trait Transport: Send {
19    fn write(&mut self, data: &[u8]) -> Result<()>;
20    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
21    fn clear(&mut self) -> Result<()>;
22    fn set_read_timeout(&mut self, timeout: Duration) -> Result<()>;
23
24    /// Reopens a dropped connection (e.g. TCPIP). Default: unsupported.
25    fn reconnect(&mut self) -> Result<()> {
26        Err(Error::Unsupported("reconnect"))
27    }
28
29    /// Pre-SCPI identity hints. Default: empty.
30    fn identity(&self) -> TransportIdentity {
31        TransportIdentity::default()
32    }
33
34    /// Applies connect options (timeouts, etc.).
35    fn configure(&mut self, opts: &ConnectOptions) -> Result<()> {
36        self.set_read_timeout(opts.io_timeout())
37    }
38}
39
40/// Boxed transport for dynamic dispatch at the session boundary.
41pub type DynTransport = Box<dyn Transport>;
42
43/// In-memory buffer transport for testing read/write plumbing.
44#[derive(Debug, Default)]
45pub struct BufferTransport {
46    pub written: Vec<u8>,
47    pub read_data: Vec<u8>,
48    read_pos: usize,
49}
50
51impl Transport for BufferTransport {
52    fn write(&mut self, data: &[u8]) -> Result<()> {
53        self.written.extend_from_slice(data);
54        Ok(())
55    }
56
57    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
58        if self.read_pos >= self.read_data.len() {
59            return Err(Error::Transport(TransportError::Closed));
60        }
61        let n = buf.len().min(self.read_data.len() - self.read_pos);
62        buf[..n].copy_from_slice(&self.read_data[self.read_pos..self.read_pos + n]);
63        self.read_pos += n;
64        Ok(n)
65    }
66
67    fn clear(&mut self) -> Result<()> {
68        self.read_pos = 0;
69        Ok(())
70    }
71
72    fn set_read_timeout(&mut self, _timeout: Duration) -> Result<()> {
73        Ok(())
74    }
75}