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