monitor_input/input_source.rs
1use anyhow::Context;
2use std::str::FromStr;
3use strum_macros::{AsRefStr, EnumString, FromRepr};
4
5/// The raw representation of an input source value.
6/// See also [`InputSource`].
7pub type InputSourceRaw = u8;
8
9#[derive(Copy, Clone, Debug, PartialEq, AsRefStr, EnumString, FromRepr)]
10#[repr(u8)]
11#[strum(ascii_case_insensitive)]
12/// An input source value.
13/// See also [`InputSourceRaw`].
14pub enum InputSource {
15 #[strum(serialize = "DP1")]
16 DisplayPort1 = 0x0F,
17 #[strum(serialize = "DP2")]
18 DisplayPort2 = 0x10,
19 Hdmi1 = 0x11,
20 Hdmi2 = 0x12,
21 UsbC1 = 0x19,
22 UsbC2 = 0x1B,
23}
24
25impl InputSource {
26 /// Get [`InputSourceRaw`].
27 /// ```
28 /// # use monitor_input::InputSource;
29 /// assert_eq!(InputSource::Hdmi1.as_raw(), 17);
30 /// ```
31 pub fn as_raw(self) -> InputSourceRaw {
32 self as InputSourceRaw
33 }
34
35 /// Get [`InputSourceRaw`] from a string.
36 /// The string is either the name of an [`InputSource`] or a number.
37 /// # Examples
38 /// ```
39 /// # use monitor_input::InputSource;
40 /// // Input strings are either an [`InputSource`] or a number.
41 /// assert_eq!(
42 /// InputSource::raw_from_str("Hdmi1").unwrap(),
43 /// InputSource::Hdmi1.as_raw()
44 /// );
45 /// assert_eq!(InputSource::raw_from_str("27").unwrap(), 27);
46 ///
47 /// // Undefined string will be an error.
48 /// assert!(InputSource::raw_from_str("xyz").is_err());
49 /// // The error message should contain the original string.
50 /// assert!(
51 /// InputSource::raw_from_str("xyz")
52 /// .unwrap_err()
53 /// .to_string()
54 /// .contains("xyz")
55 /// );
56 /// ```
57 pub fn raw_from_str(input: &str) -> anyhow::Result<InputSourceRaw> {
58 if let Ok(value) = input.parse::<InputSourceRaw>() {
59 return Ok(value);
60 }
61 InputSource::from_str(input)
62 .map(|value| value.as_raw())
63 .with_context(|| format!("\"{input}\" is not a valid input source"))
64 }
65
66 /// Get a string from [`InputSourceRaw`].
67 /// # Examples
68 /// ```
69 /// # use monitor_input::InputSource;
70 /// assert_eq!(InputSource::str_from_raw(InputSource::Hdmi1.as_raw()), "Hdmi1");
71 /// assert_eq!(InputSource::str_from_raw(17), "Hdmi1");
72 /// assert_eq!(InputSource::str_from_raw(255), "255");
73 /// ```
74 pub fn str_from_raw(value: InputSourceRaw) -> String {
75 match InputSource::from_repr(value) {
76 Some(input_source) => input_source.as_ref().to_string(),
77 None => value.to_string(),
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn input_source_from_str() {
88 assert_eq!(InputSource::from_str("Hdmi1"), Ok(InputSource::Hdmi1));
89 // Test `ascii_case_insensitive`.
90 assert_eq!(InputSource::from_str("hdmi1"), Ok(InputSource::Hdmi1));
91 assert_eq!(InputSource::from_str("HDMI1"), Ok(InputSource::Hdmi1));
92 // Test `serialize`.
93 assert_eq!(InputSource::from_str("DP1"), Ok(InputSource::DisplayPort1));
94 assert_eq!(InputSource::from_str("dp2"), Ok(InputSource::DisplayPort2));
95 // Test failures.
96 assert!(InputSource::from_str("xyz").is_err());
97 }
98}