apple_clis/shared/identifiers/device_name/
ipad.rs

1use crate::prelude::*;
2
3/// Loosely ordered from oldest to newest.
4/// newest > oldest
5#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumDiscriminants, PartialOrd, Ord)]
6pub enum IPadVariant {
7	Air {
8		screen_size: MaybeScreenSize,
9		generation: Generation,
10	},
11	Mini {
12		generation: Generation,
13	},
14	Plain {
15		generation: Generation,
16	},
17	Pro {
18		size: ScreenSize,
19		generation: Generation,
20		/// For lossless parsing
21		size_before_generation: bool,
22	},
23}
24
25impl NomFromStr for IPadVariant {
26	#[tracing::instrument(level = "trace")]
27	fn nom_from_str(input: &str) -> IResult<&str, Self> {
28		let (remaining, discriminate) = preceded(
29			ws(tag("iPad")),
30			cut(alt((
31				value(IPadVariantDiscriminants::Mini, ws(tag("mini"))),
32				value(IPadVariantDiscriminants::Air, ws(tag("Air"))),
33				value(IPadVariantDiscriminants::Pro, ws(tag("Pro"))),
34				success(IPadVariantDiscriminants::Plain),
35			))),
36		)(input)?;
37
38		#[cfg(test)]
39		trace!(
40			?discriminate,
41			remaining,
42			input,
43			"Discriminant found for parsing [IPadVariant]"
44		);
45
46		match discriminate {
47			IPadVariantDiscriminants::Air => {
48				let (remaining, screen_size) = MaybeScreenSize::nom_from_str(remaining)?;
49				let (remaining, generation) = Generation::nom_from_str(remaining)?;
50				Ok((
51					remaining,
52					IPadVariant::Air {
53						screen_size,
54						generation,
55					},
56				))
57			}
58			IPadVariantDiscriminants::Mini => {
59				let (remaining, generation) = Generation::nom_from_str(remaining)?;
60				Ok((remaining, IPadVariant::Mini { generation }))
61			}
62			IPadVariantDiscriminants::Plain => {
63				let (remaining, generation) = Generation::nom_from_str(remaining)?;
64				Ok((remaining, IPadVariant::Plain { generation }))
65			}
66			IPadVariantDiscriminants::Pro => {
67				let (remaining, (size_before_generation, (size, generation))) = alt((
68					map(
69						pair(ws(ScreenSize::nom_from_str), ws(Generation::nom_from_str)),
70						|v| (true, v),
71					),
72					map(
73						pair(ws(Generation::nom_from_str), ws(ScreenSize::nom_from_str)),
74						|(gen, ss)| (false, (ss, gen)),
75					),
76				))(remaining)?;
77				Ok((
78					remaining,
79					IPadVariant::Pro {
80						size,
81						generation,
82						size_before_generation,
83					},
84				))
85			}
86		}
87	}
88}
89
90impl Display for IPadVariant {
91	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92		match self {
93			IPadVariant::Pro {
94				size,
95				generation,
96				size_before_generation: true,
97			} => write!(f, "iPad Pro {} {}", size, generation),
98			IPadVariant::Pro {
99				size,
100				generation,
101				size_before_generation: false,
102			} => write!(f, "iPad Pro {} {}", generation, size,),
103			IPadVariant::Mini { generation } => write!(f, "iPad mini {}", generation),
104			IPadVariant::Air {
105				screen_size,
106				generation,
107			} => write!(f, "iPad Air{} {}", screen_size, generation),
108			IPadVariant::Plain { generation } => write!(f, "iPad {}", generation),
109		}
110	}
111}
112
113#[cfg(test)]
114mod test {
115	use crate::shared::assert_nom_parses;
116
117	use super::*;
118
119	#[test]
120	fn ipad_ordering() {
121		let old = IPadVariant::Plain {
122			generation: Generation::testing_num(NonZeroU8::new(1).unwrap()),
123		};
124		let new = IPadVariant::Pro {
125			size: ScreenSize::long_brackets(12.9),
126			generation: Generation::testing_num(NonZeroU8::new(2).unwrap()),
127			size_before_generation: false,
128		};
129		assert!(new > old);
130	}
131
132	#[test]
133	fn hard_coded_parsing() {
134		let examples = [
135			// "iPad Air (5th generation)",
136			// "iPad (10th generation)",
137			// "iPad mini (6th generation)",
138			// "iPad Pro (11-inch) (4th generation)",
139			// "iPad Pro (12.9-inch) (6th generation)",
140			// "iPad Air 11-inch (M2)",
141			// "iPad Air 13-inch (M2)",
142			// "iPad Pro 11-inch (M4)",
143			"iPad Pro 13-inch (M4)",
144		];
145		assert_nom_parses::<IPadVariant>(examples, |_| true)
146	}
147}