1 | //! A set of builders to generate Rust source for PHF data structures at |
---|---|
2 | //! compile time. |
3 | //! |
4 | //! The provided builders are intended to be used in a Cargo build script to |
5 | //! generate a Rust source file that will be included in a library at build |
6 | //! time. |
7 | //! |
8 | //! For more information about `rust-phf` crates, see [the `phf` crate's documentation][phf]. |
9 | //! |
10 | //! [phf]: https://docs.rs/phf |
11 | //! |
12 | //! ## Examples |
13 | //! |
14 | //! To use `phf_codegen` on build.rs, you have to add dependencies under `[build-dependencies]`: |
15 | //! |
16 | //! ```toml |
17 | //! [build-dependencies] |
18 | //! phf = { version = "0.11.1", default-features = false } |
19 | //! phf_codegen = "0.11.1" |
20 | //! ``` |
21 | //! |
22 | //! Then put code on build.rs: |
23 | //! |
24 | //! ```ignore |
25 | //! use std::env; |
26 | //! use std::fs::File; |
27 | //! use std::io::{BufWriter, Write}; |
28 | //! use std::path::Path; |
29 | //! |
30 | //! fn main() { |
31 | //! let path = Path::new(&env::var("OUT_DIR").unwrap()).join( "codegen.rs"); |
32 | //! let mut file = BufWriter::new(File::create(&path).unwrap()); |
33 | //! |
34 | //! write!( |
35 | //! &mut file, |
36 | //! "static KEYWORDS: phf::Map<&'static str, Keyword> = {}", |
37 | //! phf_codegen::Map::new() |
38 | //! .entry("loop", "Keyword::Loop") |
39 | //! .entry("continue", "Keyword::Continue") |
40 | //! .entry("break", "Keyword::Break") |
41 | //! .entry("fn", "Keyword::Fn") |
42 | //! .entry("extern", "Keyword::Extern") |
43 | //! .build() |
44 | //! ) |
45 | //! .unwrap(); |
46 | //! write!(&mut file, ";\n ").unwrap(); |
47 | //! } |
48 | //! ``` |
49 | //! |
50 | //! and lib.rs: |
51 | //! |
52 | //! ```ignore |
53 | //! #[derive(Clone)] |
54 | //! enum Keyword { |
55 | //! Loop, |
56 | //! Continue, |
57 | //! Break, |
58 | //! Fn, |
59 | //! Extern, |
60 | //! } |
61 | //! |
62 | //! include!(concat!(env!("OUT_DIR"), "/codegen.rs")); |
63 | //! |
64 | //! pub fn parse_keyword(keyword: &str) -> Option<Keyword> { |
65 | //! KEYWORDS.get(keyword).cloned() |
66 | //! } |
67 | //! ``` |
68 | //! |
69 | //! ### Byte-String Keys |
70 | //! Byte strings by default produce references to fixed-size arrays; the compiler needs a hint |
71 | //! to coerce them to slices: |
72 | //! |
73 | //! build.rs: |
74 | //! |
75 | //! ```no_run |
76 | //! use std::env; |
77 | //! use std::fs::File; |
78 | //! use std::io::{BufWriter, Write}; |
79 | //! use std::path::Path; |
80 | //! |
81 | //! fn main() { |
82 | //! let path = Path::new(&env::var("OUT_DIR").unwrap()).join( "codegen.rs"); |
83 | //! let mut file = BufWriter::new(File::create(&path).unwrap()); |
84 | //! |
85 | //! writeln!( |
86 | //! &mut file, |
87 | //! "static KEYWORDS: phf::Map<&'static [u8], Keyword> =\n {};\n ", |
88 | //! phf_codegen::Map::<&[u8]>::new() |
89 | //! .entry(b"loop", "Keyword::Loop") |
90 | //! .entry(b"continue", "Keyword::Continue") |
91 | //! .entry(b"break", "Keyword::Break") |
92 | //! .entry(b"fn", "Keyword::Fn") |
93 | //! .entry(b"extern", "Keyword::Extern") |
94 | //! .build() |
95 | //! ).unwrap(); |
96 | //! } |
97 | //! ``` |
98 | //! |
99 | //! lib.rs: |
100 | //! |
101 | //! ```ignore |
102 | //! #[derive(Clone)] |
103 | //! enum Keyword { |
104 | //! Loop, |
105 | //! Continue, |
106 | //! Break, |
107 | //! Fn, |
108 | //! Extern, |
109 | //! } |
110 | //! |
111 | //! include!(concat!(env!("OUT_DIR"), "/codegen.rs")); |
112 | //! |
113 | //! pub fn parse_keyword(keyword: &[u8]) -> Option<Keyword> { |
114 | //! KEYWORDS.get(keyword).cloned() |
115 | //! } |
116 | //! ``` |
117 | //! |
118 | //! ## Note |
119 | //! |
120 | //! The compiler's stack will overflow when processing extremely long method |
121 | //! chains (500+ calls). When generating large PHF data structures, consider |
122 | //! looping over the entries or making each call a separate statement: |
123 | //! |
124 | //! ```rust |
125 | //! let entries = [("hello", "1"), ( "world", "2")]; |
126 | //! |
127 | //! let mut builder = phf_codegen::Map::new(); |
128 | //! for &(key, value) in &entries { |
129 | //! builder.entry(key, value); |
130 | //! } |
131 | //! // ... |
132 | //! ``` |
133 | //! |
134 | //! ```rust |
135 | //! let mut builder = phf_codegen::Map::new(); |
136 | //! builder.entry("hello", "1"); |
137 | //! builder.entry("world", "2"); |
138 | //! // ... |
139 | //! ``` |
140 | |
141 | #![doc(html_root_url = "https://docs.rs/phf_codegen/0.11")] |
142 | #![allow(clippy::new_without_default)] |
143 | |
144 | use phf_shared::{FmtConst, PhfHash}; |
145 | use std::collections::HashSet; |
146 | use std::fmt; |
147 | use std::hash::Hash; |
148 | |
149 | use phf_generator::HashState; |
150 | |
151 | struct Delegate<T>(T); |
152 | |
153 | impl<T: FmtConst> fmt::Display for Delegate<T> { |
154 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
155 | self.0.fmt_const(f) |
156 | } |
157 | } |
158 | |
159 | /// A builder for the `phf::Map` type. |
160 | pub struct Map<K> { |
161 | keys: Vec<K>, |
162 | values: Vec<String>, |
163 | path: String, |
164 | } |
165 | |
166 | impl<K: Hash + PhfHash + Eq + FmtConst> Map<K> { |
167 | /// Creates a new `phf::Map` builder. |
168 | pub fn new() -> Map<K> { |
169 | // FIXME rust#27438 |
170 | // |
171 | // On Windows/MSVC there are major problems with the handling of dllimport. |
172 | // Here, because downstream build scripts only invoke generics from phf_codegen, |
173 | // the linker ends up throwing a way a bunch of static symbols we actually need. |
174 | // This works around the problem, assuming that all clients call `Map::new` by |
175 | // calling a non-generic function. |
176 | fn noop_fix_for_27438() {} |
177 | noop_fix_for_27438(); |
178 | |
179 | Map { |
180 | keys: vec![], |
181 | values: vec![], |
182 | path: String::from("::phf"), |
183 | } |
184 | } |
185 | |
186 | /// Set the path to the `phf` crate from the global namespace |
187 | pub fn phf_path(&mut self, path: &str) -> &mut Map<K> { |
188 | self.path = path.to_owned(); |
189 | self |
190 | } |
191 | |
192 | /// Adds an entry to the builder. |
193 | /// |
194 | /// `value` will be written exactly as provided in the constructed source. |
195 | pub fn entry(&mut self, key: K, value: &str) -> &mut Map<K> { |
196 | self.keys.push(key); |
197 | self.values.push(value.to_owned()); |
198 | self |
199 | } |
200 | |
201 | /// Calculate the hash parameters and return a struct implementing |
202 | /// [`Display`](::std::fmt::Display) which will print the constructed `phf::Map`. |
203 | /// |
204 | /// # Panics |
205 | /// |
206 | /// Panics if there are any duplicate keys. |
207 | pub fn build(&self) -> DisplayMap<'_, K> { |
208 | let mut set = HashSet::new(); |
209 | for key in &self.keys { |
210 | if !set.insert(key) { |
211 | panic!("duplicate key `{} `", Delegate(key)); |
212 | } |
213 | } |
214 | |
215 | let state = phf_generator::generate_hash(&self.keys); |
216 | |
217 | DisplayMap { |
218 | path: &self.path, |
219 | keys: &self.keys, |
220 | values: &self.values, |
221 | state, |
222 | } |
223 | } |
224 | } |
225 | |
226 | /// An adapter for printing a [`Map`](Map). |
227 | pub struct DisplayMap<'a, K> { |
228 | path: &'a str, |
229 | state: HashState, |
230 | keys: &'a [K], |
231 | values: &'a [String], |
232 | } |
233 | |
234 | impl<'a, K: FmtConst + 'a> fmt::Display for DisplayMap<'a, K> { |
235 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
236 | // funky formatting here for nice output |
237 | write!( |
238 | f, |
239 | "{} ::Map{{ |
240 | key:{:?} , |
241 | disps: &[", |
242 | self.path, self.state.key |
243 | )?; |
244 | |
245 | // write map displacements |
246 | for &(d1, d2) in &self.state.disps { |
247 | write!( |
248 | f, |
249 | " |
250 | ({} ,{} ),", |
251 | d1, d2 |
252 | )?; |
253 | } |
254 | |
255 | write!( |
256 | f, |
257 | " |
258 | ], |
259 | entries: &[", |
260 | )?; |
261 | |
262 | // write map entries |
263 | for &idx in &self.state.map { |
264 | write!( |
265 | f, |
266 | " |
267 | ({} ,{} ),", |
268 | Delegate(&self.keys[idx]), |
269 | &self.values[idx] |
270 | )?; |
271 | } |
272 | |
273 | write!( |
274 | f, |
275 | " |
276 | ], |
277 | }}" |
278 | ) |
279 | } |
280 | } |
281 | |
282 | /// A builder for the `phf::Set` type. |
283 | pub struct Set<T> { |
284 | map: Map<T>, |
285 | } |
286 | |
287 | impl<T: Hash + PhfHash + Eq + FmtConst> Set<T> { |
288 | /// Constructs a new `phf::Set` builder. |
289 | pub fn new() -> Set<T> { |
290 | Set { map: Map::new() } |
291 | } |
292 | |
293 | /// Set the path to the `phf` crate from the global namespace |
294 | pub fn phf_path(&mut self, path: &str) -> &mut Set<T> { |
295 | self.map.phf_path(path); |
296 | self |
297 | } |
298 | |
299 | /// Adds an entry to the builder. |
300 | pub fn entry(&mut self, entry: T) -> &mut Set<T> { |
301 | self.map.entry(entry, "()"); |
302 | self |
303 | } |
304 | |
305 | /// Calculate the hash parameters and return a struct implementing |
306 | /// [`Display`](::std::fmt::Display) which will print the constructed `phf::Set`. |
307 | /// |
308 | /// # Panics |
309 | /// |
310 | /// Panics if there are any duplicate keys. |
311 | pub fn build(&self) -> DisplaySet<'_, T> { |
312 | DisplaySet { |
313 | inner: self.map.build(), |
314 | } |
315 | } |
316 | } |
317 | |
318 | /// An adapter for printing a [`Set`](Set). |
319 | pub struct DisplaySet<'a, T> { |
320 | inner: DisplayMap<'a, T>, |
321 | } |
322 | |
323 | impl<'a, T: FmtConst + 'a> fmt::Display for DisplaySet<'a, T> { |
324 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
325 | write!(f, "{} ::Set{{ map:{} }} ", self.inner.path, self.inner) |
326 | } |
327 | } |
328 | |
329 | /// A builder for the `phf::OrderedMap` type. |
330 | pub struct OrderedMap<K> { |
331 | keys: Vec<K>, |
332 | values: Vec<String>, |
333 | path: String, |
334 | } |
335 | |
336 | impl<K: Hash + PhfHash + Eq + FmtConst> OrderedMap<K> { |
337 | /// Constructs a enw `phf::OrderedMap` builder. |
338 | pub fn new() -> OrderedMap<K> { |
339 | OrderedMap { |
340 | keys: vec![], |
341 | values: vec![], |
342 | path: String::from("::phf"), |
343 | } |
344 | } |
345 | |
346 | /// Set the path to the `phf` crate from the global namespace |
347 | pub fn phf_path(&mut self, path: &str) -> &mut OrderedMap<K> { |
348 | self.path = path.to_owned(); |
349 | self |
350 | } |
351 | |
352 | /// Adds an entry to the builder. |
353 | /// |
354 | /// `value` will be written exactly as provided in the constructed source. |
355 | pub fn entry(&mut self, key: K, value: &str) -> &mut OrderedMap<K> { |
356 | self.keys.push(key); |
357 | self.values.push(value.to_owned()); |
358 | self |
359 | } |
360 | |
361 | /// Calculate the hash parameters and return a struct implementing |
362 | /// [`Display`](::std::fmt::Display) which will print the constructed |
363 | /// `phf::OrderedMap`. |
364 | /// |
365 | /// # Panics |
366 | /// |
367 | /// Panics if there are any duplicate keys. |
368 | pub fn build(&self) -> DisplayOrderedMap<'_, K> { |
369 | let mut set = HashSet::new(); |
370 | for key in &self.keys { |
371 | if !set.insert(key) { |
372 | panic!("duplicate key `{} `", Delegate(key)); |
373 | } |
374 | } |
375 | |
376 | let state = phf_generator::generate_hash(&self.keys); |
377 | |
378 | DisplayOrderedMap { |
379 | path: &self.path, |
380 | state, |
381 | keys: &self.keys, |
382 | values: &self.values, |
383 | } |
384 | } |
385 | } |
386 | |
387 | /// An adapter for printing a [`OrderedMap`](OrderedMap). |
388 | pub struct DisplayOrderedMap<'a, K> { |
389 | path: &'a str, |
390 | state: HashState, |
391 | keys: &'a [K], |
392 | values: &'a [String], |
393 | } |
394 | |
395 | impl<'a, K: FmtConst + 'a> fmt::Display for DisplayOrderedMap<'a, K> { |
396 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
397 | write!( |
398 | f, |
399 | "{} ::OrderedMap{{ |
400 | key:{:?} , |
401 | disps: &[", |
402 | self.path, self.state.key |
403 | )?; |
404 | for &(d1, d2) in &self.state.disps { |
405 | write!( |
406 | f, |
407 | " |
408 | ({} ,{} ),", |
409 | d1, d2 |
410 | )?; |
411 | } |
412 | write!( |
413 | f, |
414 | " |
415 | ], |
416 | idxs: &[", |
417 | )?; |
418 | for &idx in &self.state.map { |
419 | write!( |
420 | f, |
421 | " |
422 | {} ,", |
423 | idx |
424 | )?; |
425 | } |
426 | write!( |
427 | f, |
428 | " |
429 | ], |
430 | entries: &[", |
431 | )?; |
432 | for (key, value) in self.keys.iter().zip(self.values.iter()) { |
433 | write!( |
434 | f, |
435 | " |
436 | ({} ,{} ),", |
437 | Delegate(key), |
438 | value |
439 | )?; |
440 | } |
441 | write!( |
442 | f, |
443 | " |
444 | ], |
445 | }}" |
446 | ) |
447 | } |
448 | } |
449 | |
450 | /// A builder for the `phf::OrderedSet` type. |
451 | pub struct OrderedSet<T> { |
452 | map: OrderedMap<T>, |
453 | } |
454 | |
455 | impl<T: Hash + PhfHash + Eq + FmtConst> OrderedSet<T> { |
456 | /// Constructs a new `phf::OrderedSet` builder. |
457 | pub fn new() -> OrderedSet<T> { |
458 | OrderedSet { |
459 | map: OrderedMap::new(), |
460 | } |
461 | } |
462 | |
463 | /// Set the path to the `phf` crate from the global namespace |
464 | pub fn phf_path(&mut self, path: &str) -> &mut OrderedSet<T> { |
465 | self.map.phf_path(path); |
466 | self |
467 | } |
468 | |
469 | /// Adds an entry to the builder. |
470 | pub fn entry(&mut self, entry: T) -> &mut OrderedSet<T> { |
471 | self.map.entry(entry, "()"); |
472 | self |
473 | } |
474 | |
475 | /// Calculate the hash parameters and return a struct implementing |
476 | /// [`Display`](::std::fmt::Display) which will print the constructed |
477 | /// `phf::OrderedSet`. |
478 | /// |
479 | /// # Panics |
480 | /// |
481 | /// Panics if there are any duplicate keys. |
482 | pub fn build(&self) -> DisplayOrderedSet<'_, T> { |
483 | DisplayOrderedSet { |
484 | inner: self.map.build(), |
485 | } |
486 | } |
487 | } |
488 | |
489 | /// An adapter for printing a [`OrderedSet`](OrderedSet). |
490 | pub struct DisplayOrderedSet<'a, T> { |
491 | inner: DisplayOrderedMap<'a, T>, |
492 | } |
493 | |
494 | impl<'a, T: FmtConst + 'a> fmt::Display for DisplayOrderedSet<'a, T> { |
495 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
496 | write!( |
497 | f, |
498 | "{} ::OrderedSet{{ map:{} }} ", |
499 | self.inner.path, self.inner |
500 | ) |
501 | } |
502 | } |
503 |
Definitions
Learn Rust with the experts
Find out more