apple_clis/shared/identifiers/
device_name.rs1use crate::prelude::*;
2
3#[derive(
5 Debug, Clone, PartialEq, derive_more::Display, derive_more::From, Serialize, Deserialize,
6)]
7#[serde(try_from = "String")]
8#[serde(into = "String")]
9pub enum DeviceName {
10 IPhone(IPhoneVariant),
11
12 IPad(IPadVariant),
13
14 #[from(ignore)]
15 #[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/inline/TODO.md"))]
16 UnImplemented(String),
17}
18
19impl From<DeviceName> for String {
20 #[tracing::instrument(level = "trace", skip(variant))]
21 fn from(variant: DeviceName) -> Self {
22 variant.to_string()
23 }
24}
25
26impl TryFrom<&str> for DeviceName {
27 type Error = <Self as FromStr>::Err;
28
29 fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
30 value.parse()
31 }
32}
33
34impl TryFrom<String> for DeviceName {
35 type Error = <Self as FromStr>::Err;
36
37 fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
38 value.parse()
39 }
40}
41
42impl_from_str_nom!(DeviceName);
43
44impl From<&IPhoneVariant> for DeviceName {
45 #[tracing::instrument(level = "trace", skip(variant))]
46 fn from(variant: &IPhoneVariant) -> Self {
47 Self::IPhone(*variant)
48 }
49}
50
51impl From<&IPadVariant> for DeviceName {
52 #[tracing::instrument(level = "trace", skip(variant))]
53 fn from(variant: &IPadVariant) -> Self {
54 Self::IPad(*variant)
55 }
56}
57
58impl From<&DeviceName> for DeviceName {
59 #[tracing::instrument(level = "trace", skip(variant))]
60 fn from(variant: &DeviceName) -> Self {
61 variant.clone()
62 }
63}
64
65pub use iphone::*;
66mod iphone;
67
68pub use ipad::*;
69mod ipad;
70
71impl DeviceName {
72 pub fn parsed_successfully(&self) -> bool {
73 !matches!(self, DeviceName::UnImplemented(_))
74 }
75
76 pub fn is_iphone(&self) -> bool {
77 matches!(self, DeviceName::IPhone(_))
78 }
79
80 pub fn is_ipad(&self) -> bool {
81 matches!(self, DeviceName::IPad(_))
82 }
83
84 pub fn get_ipad(&self) -> Option<&IPadVariant> {
85 match self {
86 DeviceName::IPad(ipad) => Some(ipad),
87 _ => None,
88 }
89 }
90
91 pub fn get_iphone(&self) -> Option<&IPhoneVariant> {
92 match self {
93 DeviceName::IPhone(iphone) => Some(iphone),
94 _ => None,
95 }
96 }
97}
98
99impl NomFromStr for DeviceName {
100 fn nom_from_str(input: &str) -> IResult<&str, Self> {
101 alt((
102 map(ws(IPadVariant::nom_from_str), DeviceName::IPad),
103 map(ws(IPhoneVariant::nom_from_str), DeviceName::IPhone),
104 map(rest, |s: &str| DeviceName::UnImplemented(s.to_owned())),
105 ))(input)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::shared::assert_nom_parses;
112
113 use super::*;
114
115 #[test]
116 fn hardcoded_parse_device_names() {
117 let examples = [
118 "iPad Air 11-inch (M2)",
119 "iPad Pro (11-inch) (4th generation)",
120 ];
121 assert_nom_parses::<DeviceName>(examples, |d| d.parsed_successfully());
122 }
123
124 #[test]
125 fn generated_parse_device_name() {
126 let examples = include!("../../../tests/device-names.json");
127 assert_nom_parses::<DeviceName>(examples, |d| d.parsed_successfully())
128 }
129}