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