Skip to main content

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}