Skip to main content

serial2/
settings.rs

1/// The settings of a serial port.
2#[derive(Clone)]
3pub struct Settings {
4	pub(crate) inner: crate::sys::Settings,
5}
6
7/// Common baud rates used by many applications and devices.
8///
9/// Note that Linux, *BSD, Windows and Apple platforms all support custom baud rates, so you are not limited to these values.
10/// It is also not guaranteed that all devices support these speeds.
11///
12/// These speeds can be useful to populate a user interface with some common options though.
13pub const COMMON_BAUD_RATES: &[u32] = &[
14	4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1500000, 2000000,
15];
16
17/// Implement a trait be delegating to an existing implementation.
18macro_rules! delegate_impl {
19	(TryFrom<$from:ty> for $for:ty as u8) => {
20		impl TryFrom<$from> for $for {
21			type Error = TryFromError<$from>;
22
23			fn try_from(value: $from) -> Result<Self, Self::Error> {
24				let narrowed = u8::try_from(value)
25					.map_err(|_| Self::unexpected(value))?;
26				Self::try_from(narrowed)
27					.map_err(|_| Self::unexpected(value))
28			}
29		}
30	};
31}
32
33/// The number of bits per character for a serial port.
34///
35/// <div>
36/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
37/// This type supports (de)serialization as a number.
38/// </div>
39#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
40#[repr(u8)]
41pub enum CharSize {
42	/// Characters of 5 bits.
43	///
44	/// <div class="item-info" style="margin-left: 0">
45	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
46	/// This variant is (de)serialized as the number <code>5</code>.
47	/// </div>
48	Bits5 = 5,
49
50	/// Characters of 6 bits.
51	///
52	/// <div class="item-info" style="margin-left: 0">
53	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
54	/// This variant is (de)serialized as the number <code>7</code>.
55	/// </div>
56	Bits6 = 6,
57
58	/// Characters of 7 bits.
59	///
60	/// <div class="item-info" style="margin-left: 0">
61	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
62	/// This variant is (de)serialized as the number <code>7</code>.
63	/// </div>
64	Bits7 = 7,
65
66	/// Characters of 8 bits.
67	///
68	/// <div class="item-info" style="margin-left: 0">
69	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
70	/// This variant is (de)serialized as the number <code>8</code>.
71	/// </div>
72	Bits8 = 8,
73}
74
75impl CharSize {
76	const EXPECTED: &'static str = "the number 5, 6, 7 or 8";
77
78	/// Get the number of data bits per character as a [`u8`].
79	pub fn as_u8(self) -> u8 {
80		self as u8
81	}
82
83	/// Create a [`TryFromError`] for an unexpected value.
84	fn unexpected<T>(unexpected: T) -> TryFromError<T> {
85		TryFromError {
86			unexpected,
87			expected: Self::EXPECTED,
88		}
89	}
90}
91
92impl std::fmt::Display for CharSize {
93	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94		std::fmt::Display::fmt(&self.as_u8(), f)
95	}
96}
97
98impl TryFrom<u8> for CharSize {
99	type Error = TryFromError<u8>;
100
101	fn try_from(value: u8) -> Result<Self, Self::Error> {
102		match value {
103			5 => Ok(Self::Bits5),
104			6 => Ok(Self::Bits6),
105			7 => Ok(Self::Bits7),
106			8 => Ok(Self::Bits8),
107			x => Err(Self::unexpected(x)),
108		}
109	}
110}
111
112delegate_impl!(TryFrom<i8> for CharSize as u8);
113delegate_impl!(TryFrom<u16> for CharSize as u8);
114delegate_impl!(TryFrom<i16> for CharSize as u8);
115delegate_impl!(TryFrom<u32> for CharSize as u8);
116delegate_impl!(TryFrom<i32> for CharSize as u8);
117delegate_impl!(TryFrom<u64> for CharSize as u8);
118delegate_impl!(TryFrom<i64> for CharSize as u8);
119delegate_impl!(TryFrom<usize> for CharSize as u8);
120delegate_impl!(TryFrom<isize> for CharSize as u8);
121
122/// The number of stop bits per character for a serial port.
123///
124/// <div>
125/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
126/// This type supports (de)serialization as a number.
127/// </div>
128#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
129#[repr(u8)]
130pub enum StopBits {
131	/// One stop bit.
132	///
133	/// <div class="item-info" style="margin-left: 0">
134	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
135	/// This variant is (de)serialized as the number <code>1</code>.
136	/// </div>
137	One = 1,
138
139	/// Two stop bit.
140	///
141	/// <div class="item-info" style="margin-left: 0">
142	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
143	/// This variant is (de)serialized as the number <code>2</code>.
144	/// </div>
145	Two = 2,
146}
147
148impl StopBits {
149	const EXPECTED: &'static str = "the number 1 or 2";
150
151	/// Get the number of stop bits as a [`u8`].
152	pub fn as_u8(self) -> u8 {
153		self as u8
154	}
155
156	/// Create a [`TryFromError`] for an unexpected value.
157	fn unexpected<T>(unexpected: T) -> TryFromError<T> {
158		TryFromError {
159			unexpected,
160			expected: Self::EXPECTED,
161		}
162	}
163}
164
165impl std::fmt::Display for StopBits {
166	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167		std::fmt::Display::fmt(&self.as_u8(), f)
168	}
169}
170
171impl TryFrom<u8> for StopBits {
172	type Error = TryFromError<u8>;
173
174	fn try_from(value: u8) -> Result<Self, Self::Error> {
175		match value {
176			1 => Ok(Self::One),
177			2 => Ok(Self::Two),
178			x => Err(Self::unexpected(x)),
179		}
180	}
181}
182
183delegate_impl!(TryFrom<i8> for StopBits as u8);
184delegate_impl!(TryFrom<u16> for StopBits as u8);
185delegate_impl!(TryFrom<i16> for StopBits as u8);
186delegate_impl!(TryFrom<u32> for StopBits as u8);
187delegate_impl!(TryFrom<i32> for StopBits as u8);
188delegate_impl!(TryFrom<u64> for StopBits as u8);
189delegate_impl!(TryFrom<i64> for StopBits as u8);
190delegate_impl!(TryFrom<usize> for StopBits as u8);
191delegate_impl!(TryFrom<isize> for StopBits as u8);
192
193/// The type of parity check for a serial port.
194///
195/// <div>
196/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
197/// This type supports (de)serialization as a string.
198/// </div>
199#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
200pub enum Parity {
201	/// Do not add a parity bit and do not check for parity.
202	///
203	/// <div class="item-info" style="margin-left: 0">
204	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
205	/// This variant is (de)serialized as the string <code>"none"</code>.
206	/// </div>
207	None,
208
209	/// Add a bit to ensure odd parity of all characters send over the serial port.
210	///
211	/// Received characters are also expected to have a parity bit and odd parity.
212	/// What happens with received characters that have invalid parity is platform and device specific.
213	///
214	///
215	/// <div class="item-info" style="margin-left: 0">
216	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
217	/// This variant is (de)serialized as the string <code>"odd"</code>.
218	/// </div>
219	Odd,
220
221	/// Add a bit to ensure even parity of all characters send over the serial port.
222	///
223	/// Received characters are also expected to have a parity bit and even parity.
224	/// What happens with received characters that have invalid parity is platform and device specific.
225	///
226	///
227	/// <div class="item-info" style="margin-left: 0">
228	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
229	/// This variant is (de)serialized as the string <code>"even"</code>.
230	/// </div>
231	Even,
232}
233
234impl Parity {
235	const EXPECTED: &'static str = "the string \"none\", \"odd\" or \"even\"";
236
237	/// Get the parity as lowercase [`&str`].
238	pub fn as_str(self) -> &'static str {
239		match self {
240			Self::None => "none",
241			Self::Odd => "odd",
242			Self::Even => "even",
243		}
244	}
245
246	/// Parse the parity from a string.
247	#[allow(clippy::should_implement_trait)] // We do implement the trait, but this is borrows the input for the error.
248	pub fn from_str(input: &str) -> Result<Self, TryFromError<&str>> {
249		match input {
250			"none" => Ok(Self::None),
251			"odd" => Ok(Self::Odd),
252			"even" => Ok(Self::Even),
253			unexpected => Err(TryFromError {
254				unexpected,
255				expected: Self::EXPECTED,
256			}),
257		}
258	}
259}
260
261impl std::fmt::Display for Parity {
262	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263		f.write_str(self.as_str())
264	}
265}
266
267impl<'a> TryFrom<&'a str> for Parity {
268	type Error = TryFromError<&'a str>;
269
270	fn try_from(value: &'a str) -> Result<Self, Self::Error> {
271		Self::from_str(value)
272	}
273}
274
275impl std::str::FromStr for Parity {
276	type Err = TryFromError<String>;
277
278	fn from_str(input: &str) -> Result<Self, Self::Err> {
279		Self::from_str(input).map_err(|e| e.convert())
280	}
281}
282
283/// The type of flow control for a serial port.
284///
285/// <div>
286/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
287/// This type supports (de)serialization as a string.
288/// </div>
289#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
290pub enum FlowControl {
291	/// Do not perform any automatic flow control.
292	///
293	/// <div class="item-info" style="margin-left: 0">
294	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
295	/// This variant is (de)serialized as the string <code>"none"</code>.
296	/// </div>
297	None,
298
299	/// Perform XON/XOFF flow control.
300	///
301	/// This is also sometimes referred to as "software flow control".
302	///
303	/// <div class="item-info" style="margin-left: 0">
304	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
305	/// This variant is (de)serialized as the string <code>"xon/xoff"</code>.
306	/// </div>
307	XonXoff,
308
309	/// Perform RTS/CTS flow control.
310	///
311	/// This is also sometimes referred to as "hardware flow control".
312	///
313	/// <div class="item-info" style="margin-left: 0">
314	/// <span class="stab portability" style="display: inline">Available on <strong>crate feature <code>serde</code></strong> only:</span>
315	/// This variant is (de)serialized as the string <code>"rts/cts"</code>.
316	/// </div>
317	RtsCts,
318}
319
320impl FlowControl {
321	const EXPECTED: &'static str = "the string \"none\", \"xon/xoff\" or \"rts/cts\"";
322
323	/// Get the flow control method as lowercase [`&str`].
324	pub fn as_str(self) -> &'static str {
325		match self {
326			Self::None => "none",
327			Self::XonXoff => "xon/xoff",
328			Self::RtsCts => "rts/cts",
329		}
330	}
331
332	/// Parse the parity from a string.
333	#[allow(clippy::should_implement_trait)] // We do implement the trait, but this is borrows the input for the error.
334	pub fn from_str(input: &str) -> Result<Self, TryFromError<&str>> {
335		match input {
336			"none" => Ok(Self::None),
337			"xon/xoff" => Ok(Self::XonXoff),
338			"rts/cts" => Ok(Self::RtsCts),
339			unexpected => Err(TryFromError {
340				unexpected,
341				expected: Self::EXPECTED,
342			}),
343		}
344	}
345}
346
347impl std::fmt::Display for FlowControl {
348	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349		f.write_str(self.as_str())
350	}
351}
352
353impl<'a> TryFrom<&'a str> for FlowControl {
354	type Error = TryFromError<&'a str>;
355
356	fn try_from(value: &'a str) -> Result<Self, Self::Error> {
357		match value {
358			"none" => Ok(Self::None),
359			"xon/xoff" => Ok(Self::XonXoff),
360			"rts/cts" => Ok(Self::RtsCts),
361			unexpected => Err(TryFromError {
362				unexpected,
363				expected: Self::EXPECTED,
364			}),
365		}
366	}
367}
368
369impl std::str::FromStr for FlowControl {
370	type Err = TryFromError<String>;
371
372	fn from_str(input: &str) -> Result<Self, Self::Err> {
373		Self::from_str(input).map_err(|e| e.convert())
374	}
375}
376
377impl Settings {
378	/// Disable all OS level input and output processing.
379	///
380	/// All input and output processing will be disabled,
381	/// and the configuration will be set for 8 bit binary communication,
382	/// one stop bit, no parity checks and no flow control.
383	///
384	/// This is usually a good starting point for manual configuration.
385	pub fn set_raw(&mut self) {
386		self.inner.set_raw();
387	}
388
389	/// Set the baud rate to be configured.
390	///
391	/// This function returns an error if the platform does not support the requested bandwidth.
392	/// Note that the device itself may also not support the requested baud rate, even if the platform does.
393	/// In that case [`SerialPort::set_configuration()`][crate::SerialPort::set_configuration] will return an error.
394	pub fn set_baud_rate(&mut self, baud_rate: u32) -> std::io::Result<()> {
395		self.inner.set_baud_rate(baud_rate)
396	}
397
398	/// Get the baud rate from the configuration.
399	pub fn get_baud_rate(&self) -> std::io::Result<u32> {
400		self.inner.get_baud_rate()
401	}
402
403	/// Set the number of bits in a character.
404	pub fn set_char_size(&mut self, char_size: CharSize) {
405		self.inner.set_char_size(char_size)
406	}
407
408	/// Get the number of bits in a character.
409	pub fn get_char_size(&self) -> std::io::Result<CharSize> {
410		self.inner.get_char_size()
411	}
412
413	/// Set the number of stop bits following each character.
414	pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
415		self.inner.set_stop_bits(stop_bits)
416	}
417
418	/// Get the number of stop bits following each character.
419	pub fn get_stop_bits(&self) -> std::io::Result<StopBits> {
420		self.inner.get_stop_bits()
421	}
422
423	/// Set the partity check.
424	pub fn set_parity(&mut self, parity: Parity) {
425		self.inner.set_parity(parity)
426	}
427
428	/// Get the partity check.
429	pub fn get_parity(&self) -> std::io::Result<Parity> {
430		self.inner.get_parity()
431	}
432
433	/// Set the flow control mechanism.
434	///
435	/// See the individual documentation of the [`FlowControl`] variants for more information.
436	pub fn set_flow_control(&mut self, flow_control: FlowControl) {
437		self.inner.set_flow_control(flow_control)
438	}
439
440	/// Get the flow control mechanism
441	pub fn get_flow_control(&self) -> std::io::Result<FlowControl> {
442		self.inner.get_flow_control()
443	}
444
445	/// Get a reference to the raw `termios` struct.
446	///
447	/// On Linux and Android this is actually a `termios2` struct.
448	/// On other Unix platforms, this is a `termios` struct.
449	///
450	/// You can use this function to access Unix specific features of the serial port.
451	/// Your code will not be cross-platform anymore if you use this.
452	#[cfg(any(feature = "doc", all(unix, feature = "unix")))]
453	#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "unix")))]
454	pub fn as_termios(&self) -> &crate::os::unix::RawTermios {
455		#[cfg(unix)] {
456			&self.inner.termios
457		}
458		#[cfg(not(unix))] {
459			unreachable!("this code is only enabled on Unix platforms or during documentation generation")
460		}
461	}
462
463	/// Get a mutable reference to the raw `termios` struct.
464	///
465	/// On Linux and Android this is actually a `termios2` struct.
466	/// On other Unix platforms, this is a `termios` struct.
467	///
468	/// You can use this function to access Unix specific features of the serial port.
469	/// Your code will not be cross-platform anymore if you use this.
470	#[cfg(any(feature = "doc", all(unix, feature = "unix")))]
471	#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "unix")))]
472	pub fn as_termios_mut(&mut self) -> &mut crate::os::unix::RawTermios {
473		#[cfg(unix)] {
474			&mut self.inner.termios
475		}
476		#[cfg(not(unix))] {
477			unreachable!("this code is only enabled on Unix platforms or during documentation generation")
478		}
479	}
480
481	/// Get a reference to the raw `DCB` struct.
482	///
483	/// You can use this function to access Windows specific features of the serial port.
484	/// Your code will not be cross-platform anymore if you use this.
485	#[cfg(any(feature = "doc", all(windows, feature = "windows")))]
486	#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "windows")))]
487	pub fn as_raw_dbc(&self) -> &crate::os::windows::DCB {
488		#[cfg(windows)] {
489			&self.inner.dcb
490		}
491		#[cfg(not(windows))] {
492			unreachable!("this code is only enabled on Windows or during documentation generation")
493		}
494	}
495
496	/// Get a mutable reference to the raw  `DCB` struct.
497	///
498	/// You can use this function to access Windows specific features of the serial port.
499	/// Your code will not be cross-platform anymore if you use this.
500	#[cfg(any(feature = "doc", all(windows, feature = "windows")))]
501	#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "windows")))]
502	pub fn as_raw_dbc_mut(&mut self) -> &mut crate::os::windows::DCB {
503		#[cfg(windows)] {
504			&mut self.inner.dcb
505		}
506		#[cfg(not(windows))] {
507			unreachable!("this code is only enabled on Windows or during documentation generation")
508		}
509	}
510}
511
512impl std::fmt::Debug for Settings {
513	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
514		f.debug_struct("Settings")
515			.field("baud_rate", &self.get_baud_rate())
516			.field("char_size", &self.get_char_size())
517			.field("stop_bits", &self.get_stop_bits())
518			.field("parity", &self.get_parity())
519			.field("flow_control", &self.get_flow_control())
520			.finish()
521	}
522}
523
524#[cfg(feature = "serde")]
525impl serde::Serialize for CharSize {
526	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
527		serializer.serialize_u8(self.as_u8())
528	}
529}
530
531#[cfg(feature = "serde")]
532impl<'de> serde::Deserialize<'de> for CharSize {
533	fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
534		struct Visitor;
535		impl serde::de::Visitor<'_> for Visitor {
536			type Value = CharSize;
537
538			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
539				formatter.write_str(Self::Value::EXPECTED)
540			}
541
542			fn visit_u64<E: serde::de::Error>(self, data: u64) -> Result<Self::Value, E> {
543				Self::Value::try_from(data)
544					.map_err(|e| E::invalid_value(serde::de::Unexpected::Unsigned(e.unexpected), &e.expected))
545			}
546		}
547
548		deserializer.deserialize_u8(Visitor)
549	}
550}
551
552#[cfg(feature = "serde")]
553impl serde::Serialize for StopBits {
554	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
555		serializer.serialize_u8(self.as_u8())
556	}
557}
558
559#[cfg(feature = "serde")]
560impl<'de> serde::Deserialize<'de> for StopBits {
561	fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
562		struct Visitor;
563		impl serde::de::Visitor<'_> for Visitor {
564			type Value = StopBits;
565
566			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
567				formatter.write_str(Self::Value::EXPECTED)
568			}
569
570			fn visit_u64<E: serde::de::Error>(self, data: u64) -> Result<Self::Value, E> {
571				Self::Value::try_from(data)
572					.map_err(|e| E::invalid_value(serde::de::Unexpected::Unsigned(e.unexpected), &e.expected))
573			}
574		}
575
576		deserializer.deserialize_u8(Visitor)
577	}
578}
579
580#[cfg(feature = "serde")]
581impl serde::Serialize for Parity {
582	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
583		serializer.serialize_str(self.as_str())
584	}
585}
586
587#[cfg(feature = "serde")]
588impl<'de> serde::Deserialize<'de> for Parity {
589	fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
590		struct Visitor;
591		impl serde::de::Visitor<'_> for Visitor {
592			type Value = Parity;
593
594			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
595				formatter.write_str(Self::Value::EXPECTED)
596			}
597
598			fn visit_str<E: serde::de::Error>(self, data: &str) -> Result<Self::Value, E> {
599				Self::Value::try_from(data)
600					.map_err(|e| E::invalid_value(serde::de::Unexpected::Str(e.unexpected), &e.expected))
601			}
602		}
603
604		deserializer.deserialize_str(Visitor)
605	}
606}
607
608#[cfg(feature = "serde")]
609impl serde::Serialize for FlowControl {
610	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
611		serializer.serialize_str(self.as_str())
612	}
613}
614
615#[cfg(feature = "serde")]
616impl<'de> serde::Deserialize<'de> for FlowControl {
617	fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
618		struct Visitor;
619		impl serde::de::Visitor<'_> for Visitor {
620			type Value = FlowControl;
621
622			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
623				formatter.write_str(Self::Value::EXPECTED)
624			}
625
626			fn visit_str<E: serde::de::Error>(self, data: &str) -> Result<Self::Value, E> {
627				Self::Value::try_from(data)
628					.map_err(|e| E::invalid_value(serde::de::Unexpected::Str(e.unexpected), &e.expected))
629			}
630		}
631
632		deserializer.deserialize_str(Visitor)
633	}
634}
635
636/// Error that can occur when converting from a primitive type.
637#[derive(Debug, Clone)]
638pub struct TryFromError<Raw> {
639	/// The unexpected value.
640	unexpected: Raw,
641
642	/// A description of what was expected instead.
643	expected: &'static str,
644}
645
646impl<Raw> TryFromError<Raw> {
647	fn convert<U: From<Raw>>(self) -> TryFromError<U> {
648		TryFromError {
649			unexpected: self.unexpected.into(),
650			expected: self.expected,
651		}
652	}
653}
654
655impl<Raw: std::fmt::Debug> std::fmt::Display for TryFromError<Raw> {
656	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
657		write!(f, "invalid value: {:?}, expected {}", self.unexpected, self.expected)
658	}
659}
660
661impl<Raw: std::fmt::Debug> std::error::Error for TryFromError<Raw> {}