reproto_core/
options.rs

1//! # Helper data structure do handle option lookups
2
3use {Diagnostics, Loc, OptionEntry, RpNumber, WithSpan};
4
5/// Helper for looking up and dealing with options.
6pub trait Options {
7    type Item: OptionEntry;
8
9    fn items(&self) -> &Vec<Loc<Self::Item>>;
10
11    fn lookup(&self, name: &str) -> Vec<Loc<&Self::Item>> {
12        self.items()
13            .iter()
14            .filter(move |o| o.name() == name)
15            .map(|option| Loc::as_ref(&option))
16            .collect()
17    }
18
19    /// Find all strings matching the given name.
20    ///
21    /// This enforces that all found values are strings, otherwise the lookup will cause an error.
22    fn find_all_strings(&self, diag: &mut Diagnostics, name: &str) -> Result<Vec<Loc<String>>, ()> {
23        let mut out = Vec::new();
24
25        for s in self.lookup(name) {
26            let (value, span) = Loc::take_pair(s);
27            let string = value.as_string().with_span(diag, &span)?;
28            out.push(Loc::new(string, span));
29        }
30
31        Ok(out)
32    }
33
34    fn find_all_u32(&self, diag: &mut Diagnostics, name: &str) -> Result<Vec<Loc<RpNumber>>, ()> {
35        let mut out = Vec::new();
36
37        for s in self.lookup(name) {
38            let (value, span) = Loc::take_pair(s);
39            let number = value.as_number().with_span(diag, &span)?;
40            out.push(Loc::new(number, span));
41        }
42
43        Ok(out)
44    }
45
46    /// Find all identifiers matching the given name.
47    ///
48    /// This enforces that all found values are identifiers, otherwise the lookup will cause an
49    /// error.
50    fn find_all_identifiers(
51        &self,
52        diag: &mut Diagnostics,
53        name: &str,
54    ) -> Result<Vec<Loc<String>>, ()> {
55        let mut out = Vec::new();
56
57        for s in self.lookup(name) {
58            let (value, span) = Loc::take_pair(s);
59            let identifier = value.as_identifier().with_span(diag, &span)?;
60            out.push(Loc::new(identifier, span));
61        }
62
63        Ok(out)
64    }
65
66    /// Optionally find exactly one identifier matching the given name.
67    ///
68    /// This enforces that all found values are identifiers, otherwise the lookup will cause an
69    /// error.
70    fn find_one_identifier(
71        &self,
72        diag: &mut Diagnostics,
73        name: &str,
74    ) -> Result<Option<Loc<String>>, ()> {
75        Ok(self.find_all_identifiers(diag, name)?.into_iter().next())
76    }
77
78    fn find_one_string(
79        &self,
80        diag: &mut Diagnostics,
81        name: &str,
82    ) -> Result<Option<Loc<String>>, ()> {
83        Ok(self.find_all_strings(diag, name)?.into_iter().next())
84    }
85
86    fn find_one_u32(
87        &self,
88        diag: &mut Diagnostics,
89        name: &str,
90    ) -> Result<Option<Loc<RpNumber>>, ()> {
91        Ok(self.find_all_u32(diag, name)?.into_iter().next())
92    }
93}
94
95impl<T> Options for Vec<Loc<T>>
96where
97    T: OptionEntry,
98{
99    type Item = T;
100
101    fn items(&self) -> &Vec<Loc<Self::Item>> {
102        self
103    }
104}