serial2/serial_port.rs
1use std::io::{IoSlice, IoSliceMut};
2use std::path::{Path, PathBuf};
3use std::time::Duration;
4
5use crate::{sys, IntoSettings, Settings};
6
7#[cfg(any(feature = "doc", all(feature = "rs4xx", target_os = "linux")))]
8use crate::rs4xx;
9
10/// A serial port.
11pub struct SerialPort {
12 inner: sys::SerialPort,
13}
14
15impl SerialPort {
16 /// Open and configure a serial port by path or name.
17 ///
18 /// On Unix systems, the `name` parameter must be a path to a TTY device.
19 /// On Windows, it must be the name of a COM device, such as COM1, COM2, etc.
20 ///
21 /// The second argument is used to configure the serial port.
22 /// For simple cases, you pass a `u32` for the baud rate.
23 /// See [`IntoSettings`] for more information.
24 ///
25 /// The library automatically uses the win32 device namespace on Windows,
26 /// so COM ports above COM9 are supported out of the box.
27 ///
28 /// # Example 1: Open a serial port with a specific baud rate and default settings.
29 /// ```
30 /// # use serial2::SerialPort;
31 /// # fn foo() -> std::io::Result<()> {
32 /// SerialPort::open("/dev/ttyUSB0", 115200)?;
33 /// # Ok(())
34 /// # }
35 /// ```
36 ///
37 /// # Example 2: Open a serial port with full control over the settings.
38 /// ```
39 /// # use serial2::{CharSize, FlowControl, Parity, SerialPort, Settings, StopBits};
40 /// # fn foo() -> std::io::Result<()> {
41 /// SerialPort::open("/dev/ttyUSB0", |mut settings: Settings| {
42 /// settings.set_raw();
43 /// settings.set_baud_rate(115200)?;
44 /// settings.set_char_size(CharSize::Bits7);
45 /// settings.set_stop_bits(StopBits::Two);
46 /// settings.set_parity(Parity::Odd);
47 /// settings.set_flow_control(FlowControl::RtsCts);
48 /// Ok(settings)
49 /// })?;
50 /// # Ok(())
51 /// # }
52 /// ```
53 pub fn open(name: impl AsRef<Path>, settings: impl IntoSettings) -> std::io::Result<Self> {
54 let mut serial_port = Self {
55 inner: sys::SerialPort::open(name.as_ref())?,
56 };
57 let mut port_settings = serial_port.get_configuration()?;
58 settings.apply_to_settings(&mut port_settings)?;
59 serial_port.set_configuration(&port_settings)?;
60 Ok(serial_port)
61 }
62
63 /// Open a connected pair of pseudo-terminals.
64 #[cfg(any(feature = "doc", all(unix, feature = "unix")))]
65 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "unix")))]
66 pub fn pair() -> std::io::Result<(Self, Self)> {
67 #[cfg(unix)] {
68 let (pty_a, pty_b) = sys::SerialPort::pair()?;
69 let mut pty_a = Self { inner: pty_a };
70 let mut pty_b = Self { inner: pty_b };
71 {
72 let mut settings = pty_a.get_configuration()?;
73 settings.set_raw();
74 pty_a.set_configuration(&settings)?;
75 }
76 {
77 let mut settings = pty_b.get_configuration()?;
78 settings.set_raw();
79 pty_b.set_configuration(&settings)?;
80 }
81
82 Ok((pty_a, pty_b))
83 }
84 #[cfg(windows)] {
85 unreachable!("this code is only enabled on Unix platforms or during documentation generation")
86 }
87 }
88
89 /// Get a list of available serial ports.
90 ///
91 /// Not currently supported on all platforms.
92 /// On unsupported platforms, this function always returns an error.
93 pub fn available_ports() -> std::io::Result<Vec<PathBuf>> {
94 sys::enumerate()
95 }
96
97 /// Configure (or reconfigure) the serial port.
98 pub fn set_configuration(&mut self, settings: &Settings) -> std::io::Result<()> {
99 self.inner.set_configuration(&settings.inner)
100 }
101
102 /// Get the current configuration of the serial port.
103 ///
104 /// This function can fail if the underlying syscall fails,
105 /// or if the serial port configuration can't be reported using [`Settings`].
106 pub fn get_configuration(&self) -> std::io::Result<Settings> {
107 Ok(Settings {
108 inner: self.inner.get_configuration()?,
109 })
110 }
111
112 /// Try to clone the serial port handle.
113 ///
114 /// The cloned object refers to the same serial port.
115 ///
116 /// Mixing reads and writes on different handles to the same serial port from different threads may lead to unexpect results.
117 /// The data may end up interleaved in unpredictable ways.
118 pub fn try_clone(&self) -> std::io::Result<Self> {
119 Ok(Self {
120 inner: self.inner.try_clone()?,
121 })
122 }
123
124 /// Read bytes from the serial port.
125 ///
126 /// This is identical to [`std::io::Read::read()`], except that this function takes a const reference `&self`.
127 /// This allows you to use the serial port concurrently from multiple threads.
128 ///
129 /// Note that there are no guarantees on which thread receives what data when multiple threads are reading from the serial port.
130 /// You should normally limit yourself to a single reading thread and a single writing thread.
131 pub fn read(&self, buf: &mut [u8]) -> std::io::Result<usize> {
132 self.inner.read(buf)
133 }
134
135 /// Read bytes from the serial port into a slice of buffers.
136 ///
137 /// This is identical to [`std::io::Read::read_vectored()`], except that this function takes a const reference `&self`.
138 /// This allows you to use the serial port concurrently from multiple threads.
139 ///
140 /// Note that there are no guarantees on which thread receives what data when multiple threads are reading from the serial port.
141 /// You should normally limit yourself to a single reading thread and a single writing thread.
142 pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> std::io::Result<usize> {
143 self.inner.read_vectored(buf)
144 }
145
146 /// Check if the implementation supports vectored reads.
147 ///
148 /// If this returns false, then [`Self::read_vectored()`] will only use the first buffer of the given slice.
149 /// All platforms except for Windows support vectored reads.
150 pub fn is_read_vectored(&self) -> bool {
151 self.inner.is_read_vectored()
152 }
153
154 /// Read the exact number of bytes required to fill the buffer from the serial port.
155 ///
156 /// This will repeatedly call `read()` until the entire buffer is filled.
157 /// Errors of the type [`std::io::ErrorKind::Interrupted`] are silently ignored.
158 /// Any other errors (including timeouts) will be returned immediately.
159 ///
160 /// If this function returns an error, it may already have read some data from the serial port into the provided buffer.
161 ///
162 /// This function is identical to [`std::io::Read::read_exact()`], except that this function takes a const reference `&self`.
163 /// This allows you to use the serial port concurrently from multiple threads.
164 ///
165 /// Note that there are no guarantees on which thread receives what data when multiple threads are reading from the serial port.
166 /// You should normally limit yourself to a single reading thread and a single writing thread.
167 pub fn read_exact(&self, buf: &mut [u8]) -> std::io::Result<()> {
168 let mut buf = buf;
169 while !buf.is_empty() {
170 match self.read(buf) {
171 Ok(0) => return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")),
172 Ok(n) => buf = &mut buf[n..],
173 Err(e) => {
174 if e.kind() != std::io::ErrorKind::Interrupted {
175 return Err(e);
176 } else {
177 continue;
178 }
179 },
180 }
181 }
182 Ok(())
183 }
184
185 /// Write bytes to the serial port.
186 ///
187 /// This is identical to [`std::io::Write::write()`], except that this function takes a const reference `&self`.
188 /// This allows you to use the serial port concurrently from multiple threads.
189 ///
190 /// Note that data written to the same serial port from multiple threads may end up interleaved at the receiving side.
191 /// You should normally limit yourself to a single reading thread and a single writing thread.
192 pub fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
193 self.inner.write(buf)
194 }
195
196 /// Write all bytes to the serial port.
197 ///
198 /// This will repeatedly call [`Self::write()`] until the entire buffer has been written.
199 /// Errors of the type [`std::io::ErrorKind::Interrupted`] are silently ignored.
200 /// Any other errors (including timeouts) will be returned immediately.
201 ///
202 /// If this function returns an error, it may already have transmitted some data from the buffer over the serial port.
203 ///
204 /// This is identical to [`std::io::Write::write_all()`], except that this function takes a const reference `&self`.
205 /// This allows you to use the serial port concurrently from multiple threads.
206 ///
207 /// Note that data written to the same serial port from multiple threads may end up interleaved at the receiving side.
208 /// You should normally limit yourself to a single reading thread and a single writing thread.
209 pub fn write_all(&self, buf: &[u8]) -> std::io::Result<()> {
210 let mut buf = buf;
211 while !buf.is_empty() {
212 match self.write(buf) {
213 Ok(0) => return Err(std::io::Error::new(std::io::ErrorKind::WriteZero, "failed to write whole buffer")),
214 Ok(n) => buf = &buf[n..],
215 Err(e) => {
216 if e.kind() != std::io::ErrorKind::Interrupted {
217 return Err(e);
218 } else {
219 continue;
220 }
221 },
222 }
223 }
224 Ok(())
225 }
226
227 /// Write bytes to the serial port from a slice of buffers.
228 ///
229 /// This is identical to [`std::io::Write::write_vectored()`], except that this function takes a const reference `&self`.
230 /// This allows you to use the serial port concurrently from multiple threads.
231 ///
232 /// Note that data written to the same serial port from multiple threads may end up interleaved at the receiving side.
233 /// You should normally limit yourself to a single reading thread and a single writing thread.
234 pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> std::io::Result<usize> {
235 self.inner.write_vectored(buf)
236 }
237
238 /// Check if the implementation supports vectored writes.
239 ///
240 /// If this returns false, then [`Self::write_vectored()`] will only use the first buffer of the given slice.
241 /// All platforms except for Windows support vectored writes.
242 pub fn is_write_vectored(&self) -> bool {
243 self.inner.is_write_vectored()
244 }
245
246 /// Flush all data queued to be written.
247 ///
248 /// This will block until the OS buffer has been fully transmitted.
249 ///
250 /// This is identical to [`std::io::Write::flush()`], except that this function takes a const reference `&self`.
251 pub fn flush(&self) -> std::io::Result<()> {
252 self.inner.flush_output()
253 }
254
255 /// Set the read timeout for the serial port.
256 ///
257 /// The timeout set by this function is an upper bound on individual calls to [`read()`][Self::read].
258 /// Other platform specific time-outs may trigger before this timeout does.
259 /// Additionally, some functions (like [`Self::read_exact`]) perform multiple calls to `read()`.
260 pub fn set_read_timeout(&mut self, timeout: Duration) -> std::io::Result<()> {
261 self.inner.set_read_timeout(timeout)
262 }
263
264 /// Get the read timeout of the serial port.
265 ///
266 /// The timeout set by this function is an upper bound on individual calls to [`read()`][Self::read].
267 /// Other platform specific time-outs may trigger before this timeout does.
268 /// Additionally, some functions (like [`Self::read_exact`]) perform multiple calls to `read()`.
269 pub fn get_read_timeout(&self) -> std::io::Result<Duration> {
270 self.inner.get_read_timeout()
271 }
272
273 /// Set the write timeout for the serial port.
274 ///
275 /// The timeout set by this function is an upper bound on individual calls to [`write()`][Self::write].
276 /// Other platform specific time-outs may trigger before this timeout does.
277 /// Additionally, some functions (like [`Self::write_all`]) perform multiple calls to `write()`.
278 pub fn set_write_timeout(&mut self, timeout: Duration) -> std::io::Result<()> {
279 self.inner.set_write_timeout(timeout)
280 }
281
282 /// Get the write timeout of the serial port.
283 ///
284 /// The timeout set by this function is an upper bound on individual calls to [`write()`][Self::write].
285 /// Other platform specific time-outs may trigger before this timeout does.
286 /// Additionally, some functions (like [`Self::write_all`]) perform multiple calls to `write()`.
287 pub fn get_write_timeout(&self) -> std::io::Result<Duration> {
288 self.inner.get_write_timeout()
289 }
290
291 /// Get the platform specific timeouts of a serial port on Windows.
292 ///
293 /// This allows for full control over the platform specifics timeouts, but it is only available on Windows.
294 ///
295 /// Also note that changing the read timeouts can easily lead to the serial port timing out on every read unless you are very careful.
296 /// Please read the whole article about serial port timeouts on MSDN before using this, including all remarks:
297 /// [https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts](https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts)
298 ///
299 /// You are strongly suggested to use [`Self::get_read_timeout()`] and [`Self::get_write_timeout()`] instead.
300 #[cfg(any(feature = "doc", all(feature = "windows", windows)))]
301 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "windows")))]
302 pub fn get_windows_timeouts(&self) -> std::io::Result<crate::os::windows::CommTimeouts> {
303 #[cfg(windows)] {
304 self.inner.get_windows_timeouts()
305 }
306 #[cfg(not(windows))] {
307 unreachable!("this code is only enabled on Windows or during documentation generation")
308 }
309 }
310
311 /// Set the platform specific timeouts of a serial port on Windows.
312 ///
313 /// This allows for full control over the platform specifics timeouts, but it is only available on Windows.
314 ///
315 /// Also note that changing the read timeouts can easily lead to the serial port timing out on every read unless you are very careful.
316 /// Please read the whole article about serial port timeouts on MSDN before using this, including all remarks:
317 /// [https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts](https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts)
318 ///
319 /// You are strongly suggested to use [`Self::set_read_timeout()`] and [`Self::set_write_timeout()`] instead.
320 #[cfg(any(feature = "doc", all(feature = "windows", windows)))]
321 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "windows")))]
322 pub fn set_windows_timeouts(&self, timeouts: &crate::os::windows::CommTimeouts) -> std::io::Result<()> {
323 #[cfg(windows)] {
324 self.inner.set_windows_timeouts(timeouts)
325 }
326 #[cfg(not(windows))] {
327 let _ = timeouts;
328 unreachable!("this code is only enabled on Windows or during documentation generation")
329 }
330 }
331
332 /// Discard the kernel input and output buffers for the serial port.
333 ///
334 /// When you write to a serial port, the data may be put in a buffer by the OS to be transmitted by the actual device later.
335 /// Similarly, data received on the device can be put in a buffer by the OS untill you read it.
336 /// This function clears both buffers: any untransmitted data and received but unread data is discarded by the OS.
337 pub fn discard_buffers(&self) -> std::io::Result<()> {
338 self.inner.discard_buffers(true, true)
339 }
340
341 /// Discard the kernel input buffers for the serial port.
342 ///
343 /// Data received on the device can be put in a buffer by the OS untill you read it.
344 /// This function clears that buffer: received but unread data is discarded by the OS.
345 ///
346 /// This is particularly useful when communicating with a device that only responds to commands that you send to it.
347 /// If you discard the input buffer before sending the command, you discard any noise that may have been received after the last command.
348 pub fn discard_input_buffer(&self) -> std::io::Result<()> {
349 self.inner.discard_buffers(true, false)
350 }
351
352 /// Discard the kernel output buffers for the serial port.
353 ///
354 /// When you write to a serial port, the data is generally put in a buffer by the OS to be transmitted by the actual device later.
355 /// This function clears that buffer: any untransmitted data is discarded by the OS.
356 pub fn discard_output_buffer(&self) -> std::io::Result<()> {
357 self.inner.discard_buffers(false, true)
358 }
359
360 /// Set the state of the Ready To Send line.
361 ///
362 /// If hardware flow control is enabled on the serial port, it is platform specific what will happen.
363 /// The function may fail with an error, or it may silently be ignored.
364 /// It may even succeed and interfere with the flow control.
365 pub fn set_rts(&self, state: bool) -> std::io::Result<()> {
366 self.inner.set_rts(state)
367 }
368
369 /// Read the state of the Clear To Send line.
370 ///
371 /// If hardware flow control is enabled on the serial port, it is platform specific what will happen.
372 /// The function may fail with an error, it may return a bogus value, or it may return the actual state of the CTS line.
373 pub fn read_cts(&self) -> std::io::Result<bool> {
374 self.inner.read_cts()
375 }
376
377 /// Set the state of the Data Terminal Ready line.
378 ///
379 /// If hardware flow control is enabled on the serial port, it is platform specific what will happen.
380 /// The function may fail with an error, or it may silently be ignored.
381 pub fn set_dtr(&self, state: bool) -> std::io::Result<()> {
382 self.inner.set_dtr(state)
383 }
384
385 /// Read the state of the Data Set Ready line.
386 ///
387 /// If hardware flow control is enabled on the serial port, it is platform specific what will happen.
388 /// The function may fail with an error, it may return a bogus value, or it may return the actual state of the DSR line.
389 pub fn read_dsr(&self) -> std::io::Result<bool> {
390 self.inner.read_dsr()
391 }
392
393 /// Read the state of the Ring Indicator line.
394 ///
395 /// This line is also sometimes also called the RNG or RING line.
396 pub fn read_ri(&self) -> std::io::Result<bool> {
397 self.inner.read_ri()
398 }
399
400 /// Read the state of the Carrier Detect (CD) line.
401 ///
402 /// This line is also called the Data Carrier Detect (DCD) line
403 /// or the Receive Line Signal Detect (RLSD) line.
404 pub fn read_cd(&self) -> std::io::Result<bool> {
405 self.inner.read_cd()
406 }
407
408 /// Set or clear the break state of the serial port.
409 ///
410 /// The serial port will hold the data line in a logical low state while the break state is enabled.
411 /// This can be detected as a break condition on the other side of the line.
412 pub fn set_break(&self, enable: bool) -> std::io::Result<()> {
413 self.inner.set_break(enable)
414 }
415
416 /// Get the RS-4xx mode of the serial port transceiver.
417 ///
418 /// This is currently only supported on Linux.
419 ///
420 /// Not all serial ports can be configured in a different mode by software.
421 /// Some serial ports are always in RS-485 or RS-422 mode,
422 /// and some may have hardware switches or jumpers to configure the transceiver.
423 /// In those cases, this function will usually report an error or [`rs4xx::TransceiverMode::Default`],
424 /// even though the serial port is configured is RS-485 or RS-422 mode.
425 ///
426 /// Note that driver support for this feature is very limited and sometimes inconsistent.
427 /// Please read all the warnings in the [`rs4xx`] module carefully.
428 #[cfg(any(feature = "doc", all(feature = "rs4xx", target_os = "linux")))]
429 #[cfg_attr(feature = "doc-cfg", doc(cfg(all(feature = "rs4xx", target_os = "linux"))))]
430 pub fn get_rs4xx_mode(&self) -> std::io::Result<rs4xx::TransceiverMode> {
431 #[cfg(all(feature = "rs4xx", target_os = "linux"))]
432 return sys::get_rs4xx_mode(&self.inner);
433 #[allow(unreachable_code)] {
434 panic!("unsupported platform");
435 }
436 }
437
438 /// Set the RS-4xx mode of the serial port transceiver.
439 ///
440 /// This is currently only supported on Linux.
441 ///
442 /// Not all serial ports can be configured in a different mode by software.
443 /// Some serial ports are always in RS-485 or RS-422 mode,
444 /// and some may have hardware switches or jumpers to configure the transceiver.
445 /// In that case, this function will usually return an error,
446 /// but the port can still be in RS-485 or RS-422 mode.
447 ///
448 /// Note that driver support for this feature is very limited and sometimes inconsistent.
449 /// Please read all the warnings in the [`rs4xx`] module carefully.
450 #[cfg(any(feature = "doc", all(feature = "rs4xx", target_os = "linux")))]
451 #[cfg_attr(feature = "doc-cfg", doc(cfg(all(feature = "rs4xx", target_os = "linux"))))]
452 pub fn set_rs4xx_mode(&self, mode: impl Into<rs4xx::TransceiverMode>) -> std::io::Result<()> {
453 #[cfg(all(feature = "rs4xx", target_os = "linux"))]
454 return sys::set_rs4xx_mode(&self.inner, &mode.into());
455 #[allow(unreachable_code)] {
456 let _ = mode;
457 panic!("unsupported platform");
458 }
459 }
460}
461
462impl std::fmt::Debug for SerialPort {
463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
464 std::fmt::Debug::fmt(&self.inner, f)
465 }
466}
467
468impl std::io::Read for SerialPort {
469 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
470 SerialPort::read(self, buf)
471 }
472
473 fn read_vectored(&mut self, buf: &mut [IoSliceMut<'_>]) -> std::io::Result<usize> {
474 SerialPort::read_vectored(self, buf)
475 }
476}
477
478impl std::io::Read for &'_ SerialPort {
479 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
480 SerialPort::read(self, buf)
481 }
482
483 fn read_vectored(&mut self, buf: &mut [IoSliceMut<'_>]) -> std::io::Result<usize> {
484 SerialPort::read_vectored(self, buf)
485 }
486}
487
488impl std::io::Write for SerialPort {
489 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
490 SerialPort::write(self, buf)
491 }
492
493 fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> std::io::Result<usize> {
494 SerialPort::write_vectored(self, buf)
495 }
496
497 fn flush(&mut self) -> std::io::Result<()> {
498 SerialPort::flush(self)
499 }
500}
501
502impl std::io::Write for &'_ SerialPort {
503 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
504 SerialPort::write(self, buf)
505 }
506
507 fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> std::io::Result<usize> {
508 SerialPort::write_vectored(self, buf)
509 }
510
511 fn flush(&mut self) -> std::io::Result<()> {
512 SerialPort::flush(self)
513 }
514}
515
516#[cfg(unix)]
517impl From<SerialPort> for std::os::unix::io::OwnedFd {
518 fn from(value: SerialPort) -> Self {
519 value.inner.file.into()
520 }
521}
522
523#[cfg(unix)]
524impl From<std::os::unix::io::OwnedFd> for SerialPort {
525 fn from(value: std::os::unix::io::OwnedFd) -> Self {
526 Self {
527 inner: sys::SerialPort::from_file(value.into()),
528 }
529 }
530}
531
532#[cfg(unix)]
533impl std::os::unix::io::AsFd for SerialPort {
534 fn as_fd(&self) -> std::os::unix::io::BorrowedFd<'_> {
535 self.inner.file.as_fd()
536 }
537}
538
539#[cfg(unix)]
540impl std::os::unix::io::AsRawFd for SerialPort {
541 fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
542 self.inner.file.as_raw_fd()
543 }
544}
545
546#[cfg(unix)]
547impl std::os::unix::io::IntoRawFd for SerialPort {
548 fn into_raw_fd(self) -> std::os::unix::io::RawFd {
549 self.inner.file.into_raw_fd()
550 }
551}
552
553#[cfg(unix)]
554impl std::os::unix::io::FromRawFd for SerialPort {
555 unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> Self {
556 use std::fs::File;
557 Self {
558 inner: sys::SerialPort::from_file(File::from_raw_fd(fd)),
559 }
560 }
561}
562
563#[cfg(windows)]
564impl From<SerialPort> for std::os::windows::io::OwnedHandle {
565 fn from(value: SerialPort) -> Self {
566 value.inner.file.into()
567 }
568}
569
570/// Convert an [`OwnedHandle`][std::os::windows::io::OwnedHandle] into a `SerialPort`.
571///
572/// The file handle must have been created with the `FILE_FLAG_OVERLAPPED` flag for the serial port to function correctly.
573#[cfg(windows)]
574impl From<std::os::windows::io::OwnedHandle> for SerialPort {
575 fn from(value: std::os::windows::io::OwnedHandle) -> Self {
576 Self {
577 inner: sys::SerialPort::from_file(value.into()),
578 }
579 }
580}
581
582#[cfg(windows)]
583impl std::os::windows::io::AsHandle for SerialPort {
584 fn as_handle(&self) -> std::os::windows::io::BorrowedHandle<'_> {
585 self.inner.file.as_handle()
586 }
587}
588
589#[cfg(windows)]
590impl std::os::windows::io::AsRawHandle for SerialPort {
591 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
592 self.inner.file.as_raw_handle()
593 }
594}
595
596#[cfg(windows)]
597impl std::os::windows::io::IntoRawHandle for SerialPort {
598 fn into_raw_handle(self) -> std::os::windows::io::RawHandle {
599 self.inner.file.into_raw_handle()
600 }
601}
602
603/// Convert an [`RawHandle`][std::os::windows::io::RawHandle] into a `SerialPort`.
604///
605/// The file handle must have been created with the `FILE_FLAG_OVERLAPPED` flag for the serial port to function correctly.
606#[cfg(windows)]
607impl std::os::windows::io::FromRawHandle for SerialPort {
608 unsafe fn from_raw_handle(handle: std::os::windows::io::RawHandle) -> Self {
609 use std::fs::File;
610 Self {
611 inner: sys::SerialPort::from_file(File::from_raw_handle(handle)),
612 }
613 }
614}