mio_serial/
lib.rs

1//! # mio-serial - Serial port I/O for mio
2//!
3//! This crate provides a serial port implementation compatable with mio.
4//!
5//! **Windows support is present but largely untested by the author**
6//!
7//! ## Links
8//!   - repo:  <https://github.com/berkowski/mio-serial>
9//!   - docs:  <https://docs.rs/mio-serial>
10#![deny(missing_docs)]
11#![warn(rust_2018_idioms)]
12
13// Enums, Structs, and Traits from the serialport crate
14pub use serialport::{
15    // Enums
16    ClearBuffer,
17    DataBits,
18    // Structs
19    Error,
20    ErrorKind,
21    FlowControl,
22    Parity,
23    // Types
24    Result,
25    // Traits
26    SerialPort,
27    SerialPortBuilder,
28    SerialPortInfo,
29    SerialPortType,
30    StopBits,
31    UsbPortInfo,
32};
33
34// Re-export port-enumerating utility function.
35pub use serialport::available_ports;
36
37// Re-export creation of SerialPortBuilder objects
38pub use serialport::new;
39
40use mio::{event::Source, Interest, Registry, Token};
41use std::io::{Error as StdIoError, ErrorKind as StdIoErrorKind, Result as StdIoResult};
42use std::time::Duration;
43
44#[cfg(unix)]
45mod os_prelude {
46    pub use mio::unix::SourceFd;
47    pub use nix::{self, libc};
48    pub use serialport::TTYPort as NativeBlockingSerialPort;
49    pub use std::os::unix::prelude::*;
50}
51
52#[cfg(windows)]
53mod os_prelude {
54    pub use mio::windows::NamedPipe;
55    pub use serialport::COMPort as NativeBlockingSerialPort;
56    pub use std::ffi::OsStr;
57    pub use std::io;
58    pub use std::mem;
59    pub use std::os::windows::ffi::OsStrExt;
60    pub use std::os::windows::io::{FromRawHandle, RawHandle};
61    pub use std::path::Path;
62    pub use std::ptr;
63    pub use winapi::um::commapi::SetCommTimeouts;
64    pub use winapi::um::fileapi::*;
65    pub use winapi::um::handleapi::INVALID_HANDLE_VALUE;
66    pub use winapi::um::winbase::{COMMTIMEOUTS, FILE_FLAG_OVERLAPPED};
67    pub use winapi::um::winnt::{
68        FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE,
69    };
70}
71use os_prelude::*;
72
73/// A [`SerialStream`].
74#[derive(Debug)]
75pub struct SerialStream {
76    #[cfg(unix)]
77    inner: serialport::TTYPort,
78    #[cfg(windows)]
79    inner: mem::ManuallyDrop<serialport::COMPort>,
80    #[cfg(windows)]
81    pipe: NamedPipe,
82}
83
84impl SerialStream {
85    /// Open a nonblocking serial port from the provided builder
86    ///
87    /// ## Example
88    ///
89    /// ```no_run
90    /// use mio_serial::{SerialPortBuilder, SerialStream};
91    /// use std::path::Path;
92    ///
93    /// let args = mio_serial::new("/dev/ttyUSB0", 9600);
94    /// let serial = SerialStream::open(&args).unwrap();
95    /// ```
96    pub fn open(builder: &crate::SerialPortBuilder) -> crate::Result<Self> {
97        log::debug!("opening serial port in synchronous blocking mode");
98        let port = NativeBlockingSerialPort::open(builder)?;
99        Self::try_from(port)
100    }
101
102    /// Create a pair of pseudo serial terminals
103    ///
104    /// ## Returns
105    /// Two connected `Serial` objects: `(master, slave)`
106    ///
107    /// ## Errors
108    /// Attempting any IO or parameter settings on the slave tty after the master
109    /// tty is closed will return errors.
110    ///
111    /// ## Examples
112    ///
113    /// ```
114    /// use mio_serial::SerialStream;
115    ///
116    /// let (master, slave) = SerialStream::pair().unwrap();
117    /// ```
118    #[cfg(unix)]
119    pub fn pair() -> crate::Result<(Self, Self)> {
120        let (master, slave) = NativeBlockingSerialPort::pair()?;
121
122        let master = Self::try_from(master)?;
123        let slave = Self::try_from(slave)?;
124
125        Ok((master, slave))
126    }
127
128    /// Sets the exclusivity of the port
129    ///
130    /// If a port is exclusive, then trying to open the same device path again
131    /// will fail.
132    ///
133    /// See the man pages for the tiocexcl and tiocnxcl ioctl's for more details.
134    ///
135    /// ## Errors
136    ///
137    /// * `Io` for any error while setting exclusivity for the port.
138    #[cfg(unix)]
139    pub fn set_exclusive(&mut self, exclusive: bool) -> crate::Result<()> {
140        self.inner.set_exclusive(exclusive)
141    }
142
143    /// Returns the exclusivity of the port
144    ///
145    /// If a port is exclusive, then trying to open the same device path again
146    /// will fail.
147    #[cfg(unix)]
148    pub fn exclusive(&self) -> bool {
149        self.inner.exclusive()
150    }
151
152    /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
153    /// same serial connection.
154    ///
155    /// Also, you must be very careful when changing the settings of a cloned `SerialPort` : since
156    /// the settings are cached on a per object basis, trying to modify them from two different
157    /// objects can cause some nasty behavior.
158    ///
159    /// This is the same as `SerialPort::try_clone()` but returns the concrete type instead.
160    ///
161    /// # Errors
162    ///
163    /// This function returns an error if the serial port couldn't be cloned.
164    ///
165    /// # DON'T USE THIS AS-IS
166    ///
167    /// This logic has never really completely worked.  Cloned file descriptors in asynchronous
168    /// code is a semantic minefield.  Are you cloning the file descriptor?  Are you cloning the
169    /// event flags on the file descriptor?  Both?  It's a bit of a mess even within one OS,
170    /// let alone across multiple OS's
171    ///
172    /// Maybe it can be done with more work, but until a clear use-case is required (or mio/tokio
173    /// gets an equivalent of the unix `AsyncFd` for async file handles, see
174    /// https://github.com/tokio-rs/tokio/issues/3781 and
175    /// https://github.com/tokio-rs/tokio/pull/3760#issuecomment-839854617) I would rather not
176    /// have any enabled code over a kind-of-works-maybe impl.  So I'll leave this code here
177    /// for now but hard-code it disabled.
178    #[cfg(any())]
179    pub fn try_clone_native(&self) -> Result<SerialStream> {
180        // This works so long as the underlying serialport-rs method doesn't do anything but
181        // duplicate the low-level file descriptor.  This is the case as of serialport-rs:4.0.1
182        let cloned_native = self.inner.try_clone_native()?;
183        #[cfg(unix)]
184        {
185            Ok(Self {
186                inner: cloned_native,
187            })
188        }
189        #[cfg(windows)]
190        {
191            // Same procedure as used in serialport-rs for duplicating raw handles
192            // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
193            // states that it can be used as well for pipes created with CreateNamedPipe as well
194            let pipe_handle = self.pipe.as_raw_handle();
195
196            let process_handle: HANDLE = unsafe { GetCurrentProcess() };
197            let mut cloned_pipe_handle: HANDLE = INVALID_HANDLE_VALUE;
198            unsafe {
199                DuplicateHandle(
200                    process_handle,
201                    pipe_handle,
202                    process_handle,
203                    &mut cloned_pipe_handle,
204                    0,
205                    TRUE,
206                    DUPLICATE_SAME_ACCESS,
207                );
208                if cloned_pipe_handle != INVALID_HANDLE_VALUE {
209                    let cloned_pipe = unsafe { NamedPipe::from_raw_handle(cloned_pipe_handle) };
210                    Ok(Self {
211                        inner: mem::ManuallyDrop::new(cloned_native),
212                        pipe: cloned_pipe,
213                    })
214                } else {
215                    Err(StdIoError::last_os_error().into())
216                }
217            }
218        }
219    }
220}
221
222impl crate::SerialPort for SerialStream {
223    /// Return the name associated with the serial port, if known.
224    #[inline(always)]
225    fn name(&self) -> Option<String> {
226        self.inner.name()
227    }
228
229    /// Returns the current baud rate.
230    ///
231    /// This function returns `None` if the baud rate could not be determined. This may occur if
232    /// the hardware is in an uninitialized state. Setting a baud rate with `set_baud_rate()`
233    /// should initialize the baud rate to a supported value.
234    #[inline(always)]
235    fn baud_rate(&self) -> crate::Result<u32> {
236        self.inner.baud_rate()
237    }
238
239    /// Returns the character size.
240    ///
241    /// This function returns `None` if the character size could not be determined. This may occur
242    /// if the hardware is in an uninitialized state or is using a non-standard character size.
243    /// Setting a baud rate with `set_char_size()` should initialize the character size to a
244    /// supported value.
245    #[inline(always)]
246    fn data_bits(&self) -> crate::Result<crate::DataBits> {
247        self.inner.data_bits()
248    }
249
250    /// Returns the flow control mode.
251    ///
252    /// This function returns `None` if the flow control mode could not be determined. This may
253    /// occur if the hardware is in an uninitialized state or is using an unsupported flow control
254    /// mode. Setting a flow control mode with `set_flow_control()` should initialize the flow
255    /// control mode to a supported value.
256    #[inline(always)]
257    fn flow_control(&self) -> crate::Result<crate::FlowControl> {
258        self.inner.flow_control()
259    }
260
261    /// Returns the parity-checking mode.
262    ///
263    /// This function returns `None` if the parity mode could not be determined. This may occur if
264    /// the hardware is in an uninitialized state or is using a non-standard parity mode. Setting
265    /// a parity mode with `set_parity()` should initialize the parity mode to a supported value.
266    #[inline(always)]
267    fn parity(&self) -> crate::Result<crate::Parity> {
268        self.inner.parity()
269    }
270
271    /// Returns the number of stop bits.
272    ///
273    /// This function returns `None` if the number of stop bits could not be determined. This may
274    /// occur if the hardware is in an uninitialized state or is using an unsupported stop bit
275    /// configuration. Setting the number of stop bits with `set_stop-bits()` should initialize the
276    /// stop bits to a supported value.
277    #[inline(always)]
278    fn stop_bits(&self) -> crate::Result<crate::StopBits> {
279        self.inner.stop_bits()
280    }
281
282    /// Returns the current timeout. This parameter is const and equal to zero and implemented due
283    /// to required for trait completeness.
284    #[inline(always)]
285    fn timeout(&self) -> Duration {
286        Duration::from_secs(0)
287    }
288
289    /// Sets the baud rate.
290    ///
291    /// ## Errors
292    ///
293    /// If the implementation does not support the requested baud rate, this function may return an
294    /// `InvalidInput` error. Even if the baud rate is accepted by `set_baud_rate()`, it may not be
295    /// supported by the underlying hardware.
296    #[inline(always)]
297    fn set_baud_rate(&mut self, baud_rate: u32) -> crate::Result<()> {
298        self.inner.set_baud_rate(baud_rate)
299    }
300
301    /// Sets the character size.
302    #[inline(always)]
303    fn set_data_bits(&mut self, data_bits: crate::DataBits) -> crate::Result<()> {
304        self.inner.set_data_bits(data_bits)
305    }
306
307    // Port settings setters
308
309    /// Sets the flow control mode.
310    #[inline(always)]
311    fn set_flow_control(&mut self, flow_control: crate::FlowControl) -> crate::Result<()> {
312        self.inner.set_flow_control(flow_control)
313    }
314
315    /// Sets the parity-checking mode.
316    #[inline(always)]
317    fn set_parity(&mut self, parity: crate::Parity) -> crate::Result<()> {
318        self.inner.set_parity(parity)
319    }
320
321    /// Sets the number of stop bits.
322    #[inline(always)]
323    fn set_stop_bits(&mut self, stop_bits: crate::StopBits) -> crate::Result<()> {
324        self.inner.set_stop_bits(stop_bits)
325    }
326
327    /// Sets the timeout for future I/O operations. This parameter is ignored but
328    /// required for trait completeness.
329    #[inline(always)]
330    fn set_timeout(&mut self, _: Duration) -> crate::Result<()> {
331        Ok(())
332    }
333
334    /// Sets the state of the RTS (Request To Send) control signal.
335    ///
336    /// Setting a value of `true` asserts the RTS control signal. `false` clears the signal.
337    ///
338    /// ## Errors
339    ///
340    /// This function returns an error if the RTS control signal could not be set to the desired
341    /// state on the underlying hardware:
342    ///
343    /// * `NoDevice` if the device was disconnected.
344    /// * `Io` for any other type of I/O error.
345    #[inline(always)]
346    fn write_request_to_send(&mut self, level: bool) -> crate::Result<()> {
347        self.inner.write_request_to_send(level)
348    }
349
350    /// Writes to the Data Terminal Ready pin
351    ///
352    /// Setting a value of `true` asserts the DTR control signal. `false` clears the signal.
353    ///
354    /// ## Errors
355    ///
356    /// This function returns an error if the DTR control signal could not be set to the desired
357    /// state on the underlying hardware:
358    ///
359    /// * `NoDevice` if the device was disconnected.
360    /// * `Io` for any other type of I/O error.
361    #[inline(always)]
362    fn write_data_terminal_ready(&mut self, level: bool) -> crate::Result<()> {
363        self.inner.write_data_terminal_ready(level)
364    }
365
366    // Functions for setting non-data control signal pins
367
368    /// Reads the state of the CTS (Clear To Send) control signal.
369    ///
370    /// This function returns a boolean that indicates whether the CTS control signal is asserted.
371    ///
372    /// ## Errors
373    ///
374    /// This function returns an error if the state of the CTS control signal could not be read
375    /// from the underlying hardware:
376    ///
377    /// * `NoDevice` if the device was disconnected.
378    /// * `Io` for any other type of I/O error.
379    #[inline(always)]
380    fn read_clear_to_send(&mut self) -> crate::Result<bool> {
381        self.inner.read_clear_to_send()
382    }
383
384    /// Reads the state of the Data Set Ready control signal.
385    ///
386    /// This function returns a boolean that indicates whether the DSR control signal is asserted.
387    ///
388    /// ## Errors
389    ///
390    /// This function returns an error if the state of the DSR control signal could not be read
391    /// from the underlying hardware:
392    ///
393    /// * `NoDevice` if the device was disconnected.
394    /// * `Io` for any other type of I/O error.
395    #[inline(always)]
396    fn read_data_set_ready(&mut self) -> crate::Result<bool> {
397        self.inner.read_data_set_ready()
398    }
399
400    // Functions for reading additional pins
401
402    /// Reads the state of the Ring Indicator control signal.
403    ///
404    /// This function returns a boolean that indicates whether the RI control signal is asserted.
405    ///
406    /// ## Errors
407    ///
408    /// This function returns an error if the state of the RI control signal could not be read from
409    /// the underlying hardware:
410    ///
411    /// * `NoDevice` if the device was disconnected.
412    /// * `Io` for any other type of I/O error.
413    #[inline(always)]
414    fn read_ring_indicator(&mut self) -> crate::Result<bool> {
415        self.inner.read_ring_indicator()
416    }
417
418    /// Reads the state of the Carrier Detect control signal.
419    ///
420    /// This function returns a boolean that indicates whether the CD control signal is asserted.
421    ///
422    /// ## Errors
423    ///
424    /// This function returns an error if the state of the CD control signal could not be read from
425    /// the underlying hardware:
426    ///
427    /// * `NoDevice` if the device was disconnected.
428    /// * `Io` for any other type of I/O error.
429    #[inline(always)]
430    fn read_carrier_detect(&mut self) -> crate::Result<bool> {
431        self.inner.read_carrier_detect()
432    }
433
434    /// Gets the number of bytes available to be read from the input buffer.
435    ///
436    /// # Errors
437    ///
438    /// This function may return the following errors:
439    ///
440    /// * `NoDevice` if the device was disconnected.
441    /// * `Io` for any other type of I/O error.
442    #[inline(always)]
443    fn bytes_to_read(&self) -> crate::Result<u32> {
444        self.inner.bytes_to_read()
445    }
446
447    /// Get the number of bytes written to the output buffer, awaiting transmission.
448    ///
449    /// # Errors
450    ///
451    /// This function may return the following errors:
452    ///
453    /// * `NoDevice` if the device was disconnected.
454    /// * `Io` for any other type of I/O error.
455    #[inline(always)]
456    fn bytes_to_write(&self) -> crate::Result<u32> {
457        self.inner.bytes_to_write()
458    }
459
460    /// Discards all bytes from the serial driver's input buffer and/or output buffer.
461    ///
462    /// # Errors
463    ///
464    /// This function may return the following errors:
465    ///
466    /// * `NoDevice` if the device was disconnected.
467    /// * `Io` for any other type of I/O error.
468    #[inline(always)]
469    fn clear(&self, buffer_to_clear: crate::ClearBuffer) -> crate::Result<()> {
470        self.inner.clear(buffer_to_clear)
471    }
472
473    /// Attempts to clone the `SerialPort`. This allow you to write and read simultaneously from the
474    /// same serial connection. Please note that if you want a real asynchronous serial port you
475    /// should look at [mio-serial](https://crates.io/crates/mio-serial) or
476    /// [tokio-serial](https://crates.io/crates/tokio-serial).
477    ///
478    /// Also, you must be very carefull when changing the settings of a cloned `SerialPort` : since
479    /// the settings are cached on a per object basis, trying to modify them from two different
480    /// objects can cause some nasty behavior.
481    ///
482    /// # Errors
483    ///
484    /// This function returns an error if the serial port couldn't be cloned.
485    #[inline(always)]
486    #[cfg(any())]
487    fn try_clone(&self) -> crate::Result<Box<dyn crate::SerialPort>> {
488        Ok(Box::new(self.try_clone_native()?))
489    }
490
491    /// Cloning is not supported for [`SerialStream`] objects
492    ///
493    /// This logic has never really completely worked.  Cloned file descriptors in asynchronous
494    /// code is a semantic minefield.  Are you cloning the file descriptor?  Are you cloning the
495    /// event flags on the file descriptor?  Both?  It's a bit of a mess even within one OS,
496    /// let alone across multiple OS's
497    ///
498    /// Maybe it can be done with more work, but until a clear use-case is required (or mio/tokio
499    /// gets an equivalent of the unix `AsyncFd` for async file handles, see
500    /// <https://github.com/tokio-rs/tokio/issues/3781> and
501    /// <https://github.com/tokio-rs/tokio/pull/3760#issuecomment-839854617>) I would rather not
502    /// have any code available over a kind-of-works-maybe impl.  So I'll leave this code here
503    /// for now but hard-code it disabled.
504    fn try_clone(&self) -> crate::Result<Box<dyn crate::SerialPort>> {
505        Err(crate::Error::new(
506            crate::ErrorKind::Io(StdIoErrorKind::Other),
507            "cloning SerialStream is not supported",
508        ))
509    }
510
511    /// Start transmitting a break
512    #[inline(always)]
513    fn set_break(&self) -> crate::Result<()> {
514        self.inner.set_break()
515    }
516
517    /// Stop transmitting a break
518    #[inline(always)]
519    fn clear_break(&self) -> crate::Result<()> {
520        self.inner.clear_break()
521    }
522}
523
524impl TryFrom<NativeBlockingSerialPort> for SerialStream {
525    type Error = crate::Error;
526    #[cfg(unix)]
527    fn try_from(port: NativeBlockingSerialPort) -> std::result::Result<Self, Self::Error> {
528        // Set the O_NONBLOCK flag.
529        log::debug!(
530            "setting O_NONBLOCK for {}",
531            port.name().unwrap_or_else(|| String::from("<UNKNOWN>"))
532        );
533        let flags = unsafe { libc::fcntl(port.as_raw_fd(), libc::F_GETFL) };
534        if flags < 0 {
535            return Err(StdIoError::last_os_error().into());
536        }
537
538        match unsafe { libc::fcntl(port.as_raw_fd(), libc::F_SETFL, flags | libc::O_NONBLOCK) } {
539            0 => Ok(SerialStream { inner: port }),
540            _ => Err(StdIoError::last_os_error().into()),
541        }
542    }
543    #[cfg(windows)]
544    fn try_from(port: NativeBlockingSerialPort) -> std::result::Result<Self, Self::Error> {
545        log::debug!(
546            "switching {} to asynchronous mode",
547            port.name().unwrap_or_else(|| String::from("<UNKNOWN>"))
548        );
549        log::debug!("reading serial port settings");
550        let name = port
551            .name()
552            .ok_or_else(|| crate::Error::new(crate::ErrorKind::NoDevice, "Empty device name"))?;
553        let baud = port.baud_rate()?;
554        let parity = port.parity()?;
555        let data_bits = port.data_bits()?;
556        let stop_bits = port.stop_bits()?;
557        let flow_control = port.flow_control()?;
558
559        let mut path = Vec::<u16>::new();
560        path.extend(OsStr::new("\\\\.\\").encode_wide());
561        path.extend(Path::new(&name).as_os_str().encode_wide());
562        path.push(0);
563
564        // Drop the port object, we'll reopen the file path as a raw handle
565        log::debug!("closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode");
566        mem::drop(port);
567
568        let handle = unsafe {
569            CreateFileW(
570                path.as_ptr(),
571                GENERIC_READ | GENERIC_WRITE,
572                0,
573                ptr::null_mut(),
574                OPEN_EXISTING,
575                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
576                0 as HANDLE,
577            )
578        };
579
580        if handle == INVALID_HANDLE_VALUE {
581            log::error!("unable to open new async file handle");
582            return Err(crate::Error::from(StdIoError::last_os_error()));
583        }
584
585        // Construct NamedPipe and COMPort from Handle
586        //
587        // We need both the NamedPipe for Read/Write and COMPort for serialport related
588        // actions.  Both are created using FromRawHandle which takes ownership of the
589        // handle which may case a double-free as both objects attempt to close the handle.
590        //
591        // Looking through the source for both NamedPipe and COMPort, NamedPipe does some
592        // cleanup in Drop while COMPort just closes the handle.
593        //
594        // We'll use a ManuallyDrop<T> for COMPort and defer cleanup to the NamedPipe
595        let pipe = unsafe { NamedPipe::from_raw_handle(handle) };
596        let mut com_port =
597            mem::ManuallyDrop::new(unsafe { serialport::COMPort::from_raw_handle(handle) });
598
599        log::debug!("re-setting serial port parameters to original values from synchronous port");
600        com_port.set_baud_rate(baud)?;
601        com_port.set_parity(parity)?;
602        com_port.set_data_bits(data_bits)?;
603        com_port.set_stop_bits(stop_bits)?;
604        com_port.set_flow_control(flow_control)?;
605        sys::override_comm_timeouts(handle)?;
606
607        Ok(Self {
608            inner: com_port,
609            pipe,
610        })
611    }
612}
613
614#[cfg(unix)]
615mod io {
616    use super::{SerialStream, StdIoError, StdIoResult};
617    use nix::libc;
618    use nix::sys::termios;
619    use std::io::ErrorKind as StdIoErrorKind;
620    use std::io::{Read, Write};
621    use std::os::unix::prelude::*;
622
623    macro_rules! uninterruptibly {
624        ($e:expr) => {{
625            loop {
626                match $e {
627                    Err(ref error) if error.kind() == StdIoErrorKind::Interrupted => {}
628                    res => break res,
629                }
630            }
631        }};
632    }
633
634    impl Read for SerialStream {
635        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
636            uninterruptibly!(match unsafe {
637                libc::read(
638                    self.as_raw_fd(),
639                    bytes.as_ptr() as *mut libc::c_void,
640                    bytes.len() as libc::size_t,
641                )
642            } {
643                x if x >= 0 => Ok(x as usize),
644                _ => Err(StdIoError::last_os_error()),
645            })
646        }
647    }
648
649    impl Write for SerialStream {
650        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
651            uninterruptibly!(match unsafe {
652                libc::write(
653                    self.as_raw_fd(),
654                    bytes.as_ptr().cast::<libc::c_void>(),
655                    bytes.len() as libc::size_t,
656                )
657            } {
658                x if x >= 0 => Ok(x as usize),
659                _ => Err(StdIoError::last_os_error()),
660            })
661        }
662
663        fn flush(&mut self) -> StdIoResult<()> {
664            uninterruptibly!(termios::tcdrain(unsafe {
665                BorrowedFd::borrow_raw(self.inner.as_raw_fd())
666            })
667            .map_err(StdIoError::from))
668        }
669    }
670
671    impl<'a> Read for &'a SerialStream {
672        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
673            uninterruptibly!(match unsafe {
674                libc::read(
675                    self.as_raw_fd(),
676                    bytes.as_ptr() as *mut libc::c_void,
677                    bytes.len() as libc::size_t,
678                )
679            } {
680                x if x >= 0 => Ok(x as usize),
681                _ => Err(StdIoError::last_os_error()),
682            })
683        }
684    }
685
686    impl<'a> Write for &'a SerialStream {
687        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
688            uninterruptibly!(match unsafe {
689                libc::write(
690                    self.as_raw_fd(),
691                    bytes.as_ptr() as *const libc::c_void,
692                    bytes.len() as libc::size_t,
693                )
694            } {
695                x if x >= 0 => Ok(x as usize),
696                _ => Err(StdIoError::last_os_error()),
697            })
698        }
699
700        fn flush(&mut self) -> StdIoResult<()> {
701            uninterruptibly!(termios::tcdrain(unsafe {
702                BorrowedFd::borrow_raw(self.inner.as_raw_fd())
703            })
704            .map_err(StdIoError::from))
705        }
706    }
707}
708
709#[cfg(windows)]
710mod io {
711    use super::{NativeBlockingSerialPort, SerialStream, StdIoResult};
712    use crate::sys;
713    use mio::windows::NamedPipe;
714    use std::io::{Read, Write};
715    use std::mem;
716    use std::os::windows::prelude::*;
717
718    impl Read for SerialStream {
719        fn read(&mut self, bytes: &mut [u8]) -> StdIoResult<usize> {
720            self.pipe.read(bytes)
721        }
722    }
723
724    impl Write for SerialStream {
725        fn write(&mut self, bytes: &[u8]) -> StdIoResult<usize> {
726            self.pipe.write(bytes)
727        }
728
729        fn flush(&mut self) -> StdIoResult<()> {
730            self.pipe.flush()
731        }
732    }
733
734    impl AsRawHandle for SerialStream {
735        fn as_raw_handle(&self) -> RawHandle {
736            self.pipe.as_raw_handle()
737        }
738    }
739
740    impl IntoRawHandle for SerialStream {
741        fn into_raw_handle(self) -> RawHandle {
742            // Since NamedPipe doesn't impl IntoRawHandle we'll use AsRawHandle and bypass
743            // NamedPipe's destructor to keep the handle in the current state
744            let manual = mem::ManuallyDrop::new(self.pipe);
745            manual.as_raw_handle()
746        }
747    }
748
749    impl FromRawHandle for SerialStream {
750        /// This method can potentially fail to override the communication timeout
751        /// value set in `sys::override_comm_timeouts` without any indication to the user.
752        unsafe fn from_raw_handle(handle: RawHandle) -> Self {
753            let inner = mem::ManuallyDrop::new(NativeBlockingSerialPort::from_raw_handle(handle));
754            let pipe = NamedPipe::from_raw_handle(handle);
755            sys::override_comm_timeouts(handle).ok();
756
757            Self { inner, pipe }
758        }
759    }
760}
761
762#[cfg(unix)]
763mod sys {
764    use super::{NativeBlockingSerialPort, SerialStream};
765    use std::os::unix::prelude::*;
766
767    impl AsRawFd for SerialStream {
768        fn as_raw_fd(&self) -> RawFd {
769            self.inner.as_raw_fd()
770        }
771    }
772
773    impl IntoRawFd for SerialStream {
774        fn into_raw_fd(self) -> RawFd {
775            self.inner.into_raw_fd()
776        }
777    }
778
779    impl FromRawFd for SerialStream {
780        unsafe fn from_raw_fd(fd: RawFd) -> Self {
781            let port = NativeBlockingSerialPort::from_raw_fd(fd);
782            Self { inner: port }
783        }
784    }
785}
786
787#[cfg(windows)]
788mod sys {
789
790    use super::os_prelude::*;
791    use super::StdIoResult;
792    /// Overrides timeout value set by serialport-rs so that the read end will
793    /// never wake up with 0-byte payload.
794    pub(crate) fn override_comm_timeouts(handle: RawHandle) -> StdIoResult<()> {
795        let mut timeouts = COMMTIMEOUTS {
796            // wait at most 1ms between two bytes (0 means no timeout)
797            ReadIntervalTimeout: 1,
798            // disable "total" timeout to wait at least 1 byte forever
799            ReadTotalTimeoutMultiplier: 0,
800            ReadTotalTimeoutConstant: 0,
801            // write timeouts are just copied from serialport-rs
802            WriteTotalTimeoutMultiplier: 0,
803            WriteTotalTimeoutConstant: 0,
804        };
805
806        let r = unsafe { SetCommTimeouts(handle, &mut timeouts) };
807        if r == 0 {
808            return Err(io::Error::last_os_error());
809        }
810        Ok(())
811    }
812}
813
814#[cfg(unix)]
815impl Source for SerialStream {
816    #[inline(always)]
817    fn register(
818        &mut self,
819        registry: &Registry,
820        token: Token,
821        interests: Interest,
822    ) -> StdIoResult<()> {
823        SourceFd(&self.as_raw_fd()).register(registry, token, interests)
824    }
825
826    #[inline(always)]
827    fn reregister(
828        &mut self,
829        registry: &Registry,
830        token: Token,
831        interests: Interest,
832    ) -> StdIoResult<()> {
833        SourceFd(&self.as_raw_fd()).reregister(registry, token, interests)
834    }
835
836    #[inline(always)]
837    fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
838        SourceFd(&self.as_raw_fd()).deregister(registry)
839    }
840}
841
842#[cfg(windows)]
843impl Source for SerialStream {
844    fn register(
845        &mut self,
846        registry: &Registry,
847        token: Token,
848        interest: Interest,
849    ) -> StdIoResult<()> {
850        self.pipe.register(registry, token, interest)
851    }
852
853    fn reregister(
854        &mut self,
855        registry: &Registry,
856        token: Token,
857        interest: Interest,
858    ) -> StdIoResult<()> {
859        self.pipe.reregister(registry, token, interest)
860    }
861
862    fn deregister(&mut self, registry: &Registry) -> StdIoResult<()> {
863        self.pipe.deregister(registry)
864    }
865}
866
867/// An extension trait for [`SerialPortBuilder`]
868///
869/// This trait adds an additional method to [`SerialPortBuilder`]:
870///
871/// - open_native_async
872///
873/// These methods mirror the [`SerialPortBuilder::open_native`] methods
874pub trait SerialPortBuilderExt {
875    /// Open a platform-specific interface to the port with the specified settings
876    fn open_native_async(self) -> Result<SerialStream>;
877}
878
879impl SerialPortBuilderExt for SerialPortBuilder {
880    /// Open a platform-specific interface to the port with the specified settings
881    fn open_native_async(self) -> Result<SerialStream> {
882        SerialStream::open(&self)
883    }
884}