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}