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 //! extern crate phf_codegen;
14 //!
15 //! use std::env;
16 //! use std::fs::File;
17 //! use std::io::{BufWriter, Write};
18 //! use std::path::Path;
19 //!
20 //! fn main() {
21 //!     let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
22 //!     let mut file = BufWriter::new(File::create(&path).unwrap());
23 //!
24 //!     writeln!(
25 //!         &mut file,
26 //!          "static KEYWORDS: phf::Map<&'static str, Keyword> = \n{};\n",
27 //!          phf_codegen::Map::new()
28 //!              .entry("loop", "Keyword::Loop")
29 //!              .entry("continue", "Keyword::Continue")
30 //!              .entry("break", "Keyword::Break")
31 //!              .entry("fn", "Keyword::Fn")
32 //!              .entry("extern", "Keyword::Extern")
33 //!              .build()
34 //!     ).unwrap();
35 //! }
36 //! ```
37 //!
38 //! lib.rs
39 //!
40 //! ```ignore
41 //! extern crate phf;
42 //!
43 //! #[derive(Clone)]
44 //! enum Keyword {
45 //!     Loop,
46 //!     Continue,
47 //!     Break,
48 //!     Fn,
49 //!     Extern,
50 //! }
51 //!
52 //! include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
53 //!
54 //! pub fn parse_keyword(keyword: &str) -> Option<Keyword> {
55 //!     KEYWORDS.get(keyword).cloned()
56 //! }
57 //! ```
58 //!
59 //! ##### Byte-String Keys
60 //! Byte strings by default produce references to fixed-size arrays; the compiler needs a hint
61 //! to coerce them to slices:
62 //!
63 //! build.rs
64 //!
65 //! ```rust,no_run
66 //! extern crate phf_codegen;
67 //!
68 //! use std::env;
69 //! use std::fs::File;
70 //! use std::io::{BufWriter, Write};
71 //! use std::path::Path;
72 //!
73 //! fn main() {
74 //!     let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
75 //!     let mut file = BufWriter::new(File::create(&path).unwrap());
76 //!
77 //!     writeln!(
78 //!         &mut file,
79 //!          "static KEYWORDS: phf::Map<&'static [u8], Keyword> = \n{};\n",
80 //!          phf_codegen::Map::<&[u8]>::new()
81 //!              .entry(b"loop", "Keyword::Loop")
82 //!              .entry(b"continue", "Keyword::Continue")
83 //!              .entry(b"break", "Keyword::Break")
84 //!              .entry(b"fn", "Keyword::Fn")
85 //!              .entry(b"extern", "Keyword::Extern")
86 //!              .build()
87 //!     ).unwrap();
88 //! }
89 //! ```
90 //!
91 //! lib.rs
92 //!
93 //! ```rust,ignore
94 //! extern crate phf;
95 //!
96 //! #[derive(Clone)]
97 //! enum Keyword {
98 //!     Loop,
99 //!     Continue,
100 //!     Break,
101 //!     Fn,
102 //!     Extern,
103 //! }
104 //!
105 //! include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
106 //!
107 //! pub fn parse_keyword(keyword: &[u8]) -> Option<Keyword> {
108 //!     KEYWORDS.get(keyword).cloned()
109 //! }
110 //! ```
111 //!
112 //! # Note
113 //!
114 //! The compiler's stack will overflow when processing extremely long method
115 //! chains (500+ calls). When generating large PHF data structures, consider
116 //! looping over the entries or making each call a separate statement:
117 //!
118 //! ```rust
119 //! let entries = [("hello", "1"), ("world", "2")];
120 //!
121 //! let mut builder = phf_codegen::Map::new();
122 //! for &(key, value) in &entries {
123 //!     builder.entry(key, value);
124 //! }
125 //! // ...
126 //! ```
127 //!
128 //! ```rust
129 //! let mut builder = phf_codegen::Map::new();
130 //! builder.entry("hello", "1");
131 //! builder.entry("world", "2");
132 //! // ...
133 //! ```
134 #![doc(html_root_url = "https://docs.rs/phf_codegen/0.7")]
135 
136 use phf_shared::{PhfHash, FmtConst};
137 use std::collections::HashSet;
138 use std::fmt;
139 use std::hash::Hash;
140 
141 use phf_generator::HashState;
142 
143 struct Delegate<T>(T);
144 
145 impl<T: FmtConst> fmt::Display for Delegate<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result146     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147         self.0.fmt_const(f)
148     }
149 }
150 
151 /// A builder for the `phf::Map` type.
152 pub struct Map<K> {
153     keys: Vec<K>,
154     values: Vec<String>,
155     path: String,
156 }
157 
158 impl<K: Hash + PhfHash + Eq + FmtConst> Map<K> {
159     /// Creates a new `phf::Map` builder.
new() -> Map<K>160     pub fn new() -> Map<K> {
161         // FIXME rust#27438
162         //
163         // On Windows/MSVC there are major problems with the handling of dllimport.
164         // Here, because downstream build scripts only invoke generics from phf_codegen,
165         // the linker ends up throwing a way a bunch of static symbols we actually need.
166         // This works around the problem, assuming that all clients call `Map::new` by
167         // calling a non-generic function.
168         fn noop_fix_for_27438() {}
169         noop_fix_for_27438();
170 
171         Map {
172             keys: vec![],
173             values: vec![],
174             path: String::from("::phf"),
175         }
176     }
177 
178     /// Set the path to the `phf` crate from the global namespace
phf_path(&mut self, path: &str) -> &mut Map<K>179     pub fn phf_path(&mut self, path: &str) -> &mut Map<K> {
180         self.path = path.to_owned();
181         self
182     }
183 
184     /// Adds an entry to the builder.
185     ///
186     /// `value` will be written exactly as provided in the constructed source.
entry(&mut self, key: K, value: &str) -> &mut Map<K>187     pub fn entry(&mut self, key: K, value: &str) -> &mut Map<K> {
188         self.keys.push(key);
189         self.values.push(value.to_owned());
190         self
191     }
192 
193     /// Calculate the hash parameters and return a struct implementing
194     /// [`Display`](::std::fmt::Display) which will print the constructed `phf::Map`.
195     ///
196     /// # Panics
197     ///
198     /// Panics if there are any duplicate keys.
build(&self) -> DisplayMap<K>199     pub fn build(&self) -> DisplayMap<K> {
200         let mut set = HashSet::new();
201         for key in &self.keys {
202             if !set.insert(key) {
203                 panic!("duplicate key `{}`", Delegate(key));
204             }
205         }
206 
207         let state = phf_generator::generate_hash(&self.keys);
208 
209         DisplayMap {
210             path: &self.path,
211             keys: &self.keys,
212             values: &self.values,
213             state,
214         }
215     }
216 }
217 
218 /// An adapter for printing a [`Map`](Map).
219 pub struct DisplayMap<'a, K> {
220     path: &'a str,
221     state: HashState,
222     keys: &'a [K],
223     values: &'a [String],
224 
225 }
226 
227 impl<'a, K: FmtConst + 'a> fmt::Display for DisplayMap<'a, K> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result228     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229         // funky formatting here for nice output
230         write!(f,
231                "{}::Map {{
232     key: {:?},
233     disps: {}::Slice::Static(&[",
234                self.path, self.state.key, self.path)?;
235 
236         // write map displacements
237         for &(d1, d2) in &self.state.disps {
238             write!(f,
239                    "
240         ({}, {}),",
241                    d1,
242                    d2)?;
243         }
244 
245         write!(f,
246                "
247     ]),
248     entries: {}::Slice::Static(&[", self.path)?;
249 
250         // write map entries
251         for &idx in &self.state.map {
252             write!(f,
253                    "
254         ({}, {}),",
255                    Delegate(&self.keys[idx]),
256                    &self.values[idx])?;
257         }
258 
259         write!(f,
260                "
261     ]),
262 }}")
263     }
264 }
265 
266 /// A builder for the `phf::Set` type.
267 pub struct Set<T> {
268     map: Map<T>,
269 }
270 
271 impl<T: Hash + PhfHash + Eq + FmtConst> Set<T> {
272     /// Constructs a new `phf::Set` builder.
new() -> Set<T>273     pub fn new() -> Set<T> {
274         Set {
275             map: Map::new(),
276         }
277     }
278 
279     /// Set the path to the `phf` crate from the global namespace
phf_path(&mut self, path: &str) -> &mut Set<T>280     pub fn phf_path(&mut self, path: &str) -> &mut Set<T> {
281         self.map.phf_path(path);
282         self
283     }
284 
285     /// Adds an entry to the builder.
entry(&mut self, entry: T) -> &mut Set<T>286     pub fn entry(&mut self, entry: T) -> &mut Set<T> {
287         self.map.entry(entry, "()");
288         self
289     }
290 
291     /// Calculate the hash parameters and return a struct implementing
292     /// [`Display`](::std::fmt::Display) which will print the constructed `phf::Set`.
293     ///
294     /// # Panics
295     ///
296     /// Panics if there are any duplicate keys.
build(&self) -> DisplaySet<T>297     pub fn build(&self) -> DisplaySet<T> {
298         DisplaySet {
299             inner: self.map.build()
300         }
301     }
302 }
303 
304 /// An adapter for printing a [`Set`](Set).
305 pub struct DisplaySet<'a, T: 'a> {
306     inner: DisplayMap<'a, T>,
307 }
308 
309 impl<'a, T: FmtConst + 'a> fmt::Display for DisplaySet<'a, T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result310     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311         write!(f, "{}::Set {{ map: {} }}", self.inner.path, self.inner)
312     }
313 }
314