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
144use phf_shared::{FmtConst, PhfHash};
145use std::collections::HashSet;
146use std::fmt;
147use std::hash::Hash;
148
149use phf_generator::HashState;
150
151struct Delegate<T>(T);
152
153impl<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.
160pub struct Map<K> {
161 keys: Vec<K>,
162 values: Vec<String>,
163 path: String,
164}
165
166impl<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).
227pub struct DisplayMap<'a, K> {
228 path: &'a str,
229 state: HashState,
230 keys: &'a [K],
231 values: &'a [String],
232}
233
234impl<'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.
283pub struct Set<T> {
284 map: Map<T>,
285}
286
287impl<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).
319pub struct DisplaySet<'a, T> {
320 inner: DisplayMap<'a, T>,
321}
322
323impl<'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.
330pub struct OrderedMap<K> {
331 keys: Vec<K>,
332 values: Vec<String>,
333 path: String,
334}
335
336impl<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).
388pub struct DisplayOrderedMap<'a, K> {
389 path: &'a str,
390 state: HashState,
391 keys: &'a [K],
392 values: &'a [String],
393}
394
395impl<'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.
451pub struct OrderedSet<T> {
452 map: OrderedMap<T>,
453}
454
455impl<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).
490pub struct DisplayOrderedSet<'a, T> {
491 inner: DisplayOrderedMap<'a, T>,
492}
493
494impl<'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

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more