1mod range;
6
7use std::{io, iter};
8
9pub use range::{CreateRangeError, ParseRangeError, Range, RangeElement};
10
11#[derive(Debug, PartialEq)]
12pub enum ParseArgumentsError {
13 Help,
14 CreateRangeError(range::CreateRangeError),
15 ParseRangeError(range::ParseRangeError),
16}
17
18impl From<range::ParseRangeError> for ParseArgumentsError {
19 fn from(error: range::ParseRangeError) -> Self {
20 ParseArgumentsError::ParseRangeError(error)
21 }
22}
23
24impl From<range::CreateRangeError> for ParseArgumentsError {
25 fn from(error: range::CreateRangeError) -> Self {
26 ParseArgumentsError::CreateRangeError(error)
27 }
28}
29
30pub fn parse_arguments<T: AsRef<str>>(args: &[T]) -> Result<Vec<Range>, ParseArgumentsError> {
31 if args.iter().any(|s| s.as_ref() == "-h" || s.as_ref() == "--help") {
32 Err(ParseArgumentsError::Help)
33 }
34 else {
35 args.iter()
36 .flat_map(|arg| arg.as_ref().split(","))
37 .map(|r| r.parse::<Range>().map_err(ParseArgumentsError::ParseRangeError))
38 .collect()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::{ParseArgumentsError, Range, parse_arguments};
45
46 #[test]
47 fn no_arguments() {
48 let result = parse_arguments(&Vec::<&str>::new()).unwrap();
49 assert_eq!(result, Vec::<Range>::new());
50 }
51
52 #[test]
53 fn single_number() {
54 let result = parse_arguments(&["1"]).unwrap();
55 let expected = vec![Range::new(1, 1, 1).unwrap()];
56 assert_eq!(result, expected);
57 }
58
59 #[test]
60 fn single_range() {
61 let result = parse_arguments(&["1-10"]).unwrap();
62 assert_eq!(result, vec![Range::new(1, 10, 1).unwrap()]);
63 }
64
65 #[test]
66 fn single_range_with_step() {
67 let result = parse_arguments(&["1-10/2"]).unwrap();
68 assert_eq!(result, vec![Range::new(1, 10, 2).unwrap()]);
69 }
70
71 #[test]
72 fn single_arg_multiple_ranges_with_steps() {
73 let result = parse_arguments(&["1-10/2,12-25/3"]).unwrap();
74 assert_eq!(result, vec![Range::new(1, 10, 2).unwrap(), Range::new(12, 25, 3).unwrap()]);
75 }
76
77 #[test]
78 fn multiple_args() {
79 let result = parse_arguments(&["1-10/2", "12-25/3"]).unwrap();
80 assert_eq!(result, vec![Range::new(1, 10, 2).unwrap(), Range::new(12, 25, 3).unwrap()]);
81 }
82
83 #[test]
84 fn multiple_args_multiple_ranges() {
85 let result = parse_arguments(&["1-10/2,12-25/3", "30-40/5"]).unwrap();
86 assert_eq!(
87 result,
88 vec![
89 Range::new(1, 10, 2).unwrap(),
90 Range::new(12, 25, 3).unwrap(),
91 Range::new(30, 40, 5).unwrap()
92 ]
93 );
94 }
95
96 #[test]
97 fn short_help() {
98 let result = parse_arguments(&["-h"]);
99 assert_eq!(result.unwrap_err(), ParseArgumentsError::Help);
100 }
101
102 #[test]
103 fn long_help() {
104 let result = parse_arguments(&["--help"]);
105 assert_eq!(result.unwrap_err(), ParseArgumentsError::Help);
106 }
107
108 #[test]
109 fn long_help_with_other_args() {
110 let result = parse_arguments(&["1-10/2", "--help"]);
111 assert_eq!(result.unwrap_err(), ParseArgumentsError::Help);
112 }
113}
114
115pub fn print_usage(program: &str) {
116 eprintln!("Usage: {program} <range>[,<range>]...");
117 eprintln!("Read standard input and print the lines selected by the given ranges.");
118 eprintln!();
119 eprintln!(" --help display this help and exit");
120}
121
122pub fn select_elements<T>(
123 source: impl iter::Iterator<Item = T>,
124 ranges: &[Range],
125) -> impl iter::Iterator<Item = T> {
126 source.enumerate().filter_map(|(i, elem)| {
127 if ranges.iter().any(|r| r.contains(i + 1)) {
128 Some(elem)
129 }
130 else {
131 None
132 }
133 })
134}
135
136pub fn print_selected_lines(ranges: &[Range]) {
137 select_elements(io::stdin().lines(), ranges).for_each(|line| println!("{}", line.unwrap()))
138}