1extern crate zcfg;
2extern crate itertools;
3
4use std::collections::HashMap;
5use itertools::Itertools;
6use zcfg::ConfigMetadata;
7use zcfg::InitErr;
8
9#[derive(Debug, PartialEq, Eq, Clone)]
10pub enum FlagInitErr {
11 UndefinedArg(String),
12 InitErr(InitErr),
13}
14
15pub struct FlagParser;
16
17impl FlagParser {
18 pub fn new() -> FlagParser {
19 FlagParser
20 }
21
22 pub fn parse_from_args<I: Iterator<Item = String>>(&self, args: I) -> Result<(), Vec<FlagInitErr>> {
23 let initializers = zcfg::STATIC_CONFIG_INITIALIZERS.read()
24 .expect("initializers were poisoned");
25
26 let mut initializer_meta_sorted =
27 initializers.iter()
28 .map(|i| i.metadata().clone())
29 .collect::<Vec<ConfigMetadata>>();
30 initializer_meta_sorted.sort_by(|a, b| a.config_name().cmp(b.config_name()));
31
32 let flag_name_conflicts: Vec<(String, Vec<ConfigMetadata>)> =
33 initializer_meta_sorted.into_iter()
34 .group_by(|i| i.config_name().to_owned())
35 .into_iter()
36 .map(|(key, metadata_objects)| (key, metadata_objects.collect::<Vec<ConfigMetadata>>()))
37 .filter(|&(_, ref metadata_objects)| metadata_objects.len() > 1)
38 .collect();
39
40 assert_eq!(flag_name_conflicts, Vec::new());
42
43 let arg_elements = args.map(|content| {
44 if content == "--".to_owned() {
45 ArgComponent::Terminator
46 } else if content.starts_with("--") {
47 if content.contains('=') {
49 ArgComponent::CompleteArg(content)
50 } else {
51 ArgComponent::ArgPrefix(content)
52 }
53 } else {
54 ArgComponent::ArgSuffix(content)
55 }
56 })
57 .peekable()
58 .batching(|mut it| {
59 let first = it.next();
60 if first.is_none() { return None }
61 match first {
62 None => None,
63 Some(ArgComponent::Terminator) => None,
64 Some(ArgComponent::ArgSuffix(value)) => {
65 Some(Err(format!("Arg element [{}] did not have a corresponding key", value)))
66 },
67 Some(ArgComponent::CompleteArg(name_and_value)) => {
68 let eq_byte_idx = name_and_value.find('=').unwrap();
69 let (name, value_plus_eq) = name_and_value.split_at(eq_byte_idx);
70 Some(Ok(ArgCapture {
71 label: name.chars().skip(2 ).collect::<String>(),
72 value: Some(value_plus_eq.chars().skip(1 ).collect::<String>()),
73 }))
74 }
75 Some(ArgComponent::ArgPrefix(name)) => {
76 let mut value_opt = None;
77 if let Some(&ArgComponent::ArgSuffix(ref s)) = it.peek() {
78 value_opt = Some(s.clone())
80 }
81 match value_opt {
82 Some(value) => {
83 it.next();
85 Some(Ok(ArgCapture {
86 label: name.chars().skip(2 ).collect::<String>(),
87 value: Some(value.to_owned()),
88 }))
89 },
90 None => {
91 Some(Ok(ArgCapture {
92 label: name.chars().skip(2 ).collect::<String>(),
93 value: None,
94 }))
95 }
96 }
97 }
98 }
99 })
100 .collect::<Vec<Result<ArgCapture, String>>>();
101
102
103 let mut captures = Vec::new();
104 for arg in arg_elements.into_iter() {
105 if let Err(e) = arg {
106 panic!(e)
107 }
108 captures.push(arg.unwrap());
109 }
110
111
112 let mut config_name_to_idx = HashMap::new();
113 for (idx, e) in initializers.iter().enumerate() {
114 config_name_to_idx.insert(e.config_name().clone(), idx);
115 }
116
117 let mut set_errs = Vec::new();
118 for capture in captures.into_iter() {
119 let label: &str = &capture.label;
120 if !config_name_to_idx.contains_key(label) {
121 set_errs.push(FlagInitErr::UndefinedArg(capture.label.clone()))
122 } else {
123 let config_idx = config_name_to_idx.get(label).unwrap();
124 let initializer_ref = initializers.get(*config_idx).unwrap();
125 let result = match capture.value {
126 None => initializer_ref.set_statically("True"),
127 Some(ref v) => initializer_ref.set_statically(v)
128 };
129
130 if result.is_err() {
131 set_errs.push(FlagInitErr::InitErr(result.err().unwrap()))
132 }
133 }
134 }
135 if set_errs.is_empty() {
136 Ok(())
137 } else {
138 Err(set_errs)
139 }
140 }
141}
142
143#[derive(Clone, Debug, PartialEq, Eq)]
144enum ArgComponent {
145 CompleteArg(String),
146 ArgPrefix(String),
147 ArgSuffix(String),
148 Terminator,
149}
150
151#[derive(Clone,Debug, PartialEq, Eq)]
152struct ArgCapture {
153 pub label: String,
154 pub value: Option<String>
155}