dictgen/
map.rs

1#[cfg(feature = "codegen")]
2pub struct MapGen<'g> {
3    pub(crate) gen: crate::DictGen<'g>,
4    pub(crate) unicase: bool,
5    pub(crate) unicode: bool,
6}
7
8#[cfg(feature = "codegen")]
9impl MapGen<'_> {
10    pub fn unicase(mut self, yes: bool) -> Self {
11        self.unicase = yes;
12        self
13    }
14
15    pub fn unicode(mut self, yes: bool) -> Self {
16        self.unicode = yes;
17        self
18    }
19
20    pub fn write<W: std::io::Write, V: std::fmt::Display>(
21        &self,
22        file: &mut W,
23        data: impl Iterator<Item = (impl AsRef<str>, V)>,
24    ) -> Result<(), std::io::Error> {
25        let mut data: Vec<_> = data.collect();
26        data.sort_unstable_by_key(|v| unicase::UniCase::new(v.0.as_ref().to_owned()));
27
28        let name = self.gen.name;
29        let key_type = self.key_type();
30        let value_type = self.gen.value_type;
31
32        let mut smallest = usize::MAX;
33        let mut largest = usize::MIN;
34        for (key, _) in data.iter() {
35            let key = key.as_ref();
36            smallest = std::cmp::min(smallest, key.len());
37            largest = std::cmp::max(largest, key.len());
38        }
39        if largest == 0 {
40            smallest = 0;
41        }
42
43        writeln!(
44            file,
45            "pub static {name}: dictgen::Map<{key_type}, {value_type}> = dictgen::Map {{"
46        )?;
47
48        match (self.unicase, self.unicode) {
49            (true, true) => {
50                let mut builder = phf_codegen::Map::new();
51                let data = data
52                    .iter()
53                    .map(|(key, value)| {
54                        let key = key.as_ref();
55                        (
56                            if key.is_ascii() {
57                                crate::InsensitiveStr::Ascii(key)
58                            } else {
59                                crate::InsensitiveStr::Unicode(key)
60                            },
61                            value.to_string(),
62                        )
63                    })
64                    .collect::<Vec<_>>();
65                for (key, value) in data.iter() {
66                    builder.entry(key, value.as_str());
67                }
68                let builder = builder.build();
69                writeln!(file, "    map: {builder},")?;
70            }
71            (true, false) => {
72                let mut builder = phf_codegen::Map::new();
73                let data = data
74                    .iter()
75                    .map(|(key, value)| (crate::InsensitiveAscii(key.as_ref()), value.to_string()))
76                    .collect::<Vec<_>>();
77                for (key, value) in data.iter() {
78                    builder.entry(key, value.as_str());
79                }
80                let builder = builder.build();
81                writeln!(file, "    map: {builder},")?;
82            }
83            (false, _) => {
84                let mut builder = phf_codegen::Map::new();
85                let data = data
86                    .iter()
87                    .map(|(key, value)| (key, value.to_string()))
88                    .collect::<Vec<_>>();
89                for (key, value) in data.iter() {
90                    builder.entry(key.as_ref(), value.as_str());
91                }
92                let builder = builder.build();
93                writeln!(file, "    map: {builder},")?;
94            }
95        }
96
97        writeln!(file, "    range: {smallest}..={largest},")?;
98        writeln!(file, "}};")?;
99
100        Ok(())
101    }
102
103    fn key_type(&self) -> &'static str {
104        match (self.unicase, self.unicode) {
105            (true, true) => "dictgen::InsensitiveStr<'static>",
106            (true, false) => "dictgen::InsensitiveAscii<'static>",
107            (false, _) => "&'static str",
108        }
109    }
110}
111
112pub struct Map<K: 'static, V: 'static> {
113    pub map: phf::Map<K, V>,
114    pub range: std::ops::RangeInclusive<usize>,
115}
116
117impl<V> Map<crate::InsensitiveStr<'_>, V> {
118    #[inline]
119    pub fn find(&self, word: &'_ unicase::UniCase<&str>) -> Option<&V> {
120        if self.range.contains(&word.len()) {
121            self.map.get(&(*word).into())
122        } else {
123            None
124        }
125    }
126}
127
128impl<V> Map<crate::InsensitiveAscii<'_>, V> {
129    #[inline]
130    pub fn find(&self, word: &'_ unicase::Ascii<&str>) -> Option<&V> {
131        if self.range.contains(&word.len()) {
132            self.map.get(&(*word).into())
133        } else {
134            None
135        }
136    }
137}
138
139impl<V> Map<&str, V> {
140    #[inline]
141    pub fn find(&self, word: &'_ &str) -> Option<&V> {
142        if self.range.contains(&word.len()) {
143            self.map.get(word)
144        } else {
145            None
146        }
147    }
148}