| #[cfg(feature = "phf")] |
| extern crate phf_codegen; |
| extern crate unicase; |
| |
| use unicase::UniCase; |
| |
| use std::env; |
| use std::fs::File; |
| use std::io::prelude::*; |
| use std::io::BufWriter; |
| use std::path::Path; |
| |
| use std::collections::BTreeMap; |
| |
| use mime_types::MIME_TYPES; |
| |
| #[path = "src/mime_types.rs"] |
| mod mime_types; |
| |
| #[cfg(feature = "phf")] |
| const PHF_PATH: &str = "::impl_::phf"; |
| |
| fn main() { |
| let out_dir = env::var("OUT_DIR").unwrap(); |
| let dest_path = Path::new(&out_dir).join("mime_types_generated.rs"); |
| let mut outfile = BufWriter::new(File::create(dest_path).unwrap()); |
| |
| #[cfg(feature = "phf")] |
| build_forward_map(&mut outfile); |
| |
| #[cfg(feature = "rev-mappings")] |
| build_rev_map(&mut outfile); |
| } |
| |
| // Build forward mappings (ext -> mime type) |
| #[cfg(feature = "phf")] |
| fn build_forward_map<W: Write>(out: &mut W) { |
| use phf_codegen::Map as PhfMap; |
| |
| let mut forward_map = PhfMap::new(); |
| forward_map.phf_path(PHF_PATH); |
| |
| let mut map_entries: Vec<(&str, Vec<&str>)> = Vec::new(); |
| |
| for &(key, types) in MIME_TYPES { |
| if let Some(&mut (key_, ref mut values)) = map_entries.last_mut() { |
| // deduplicate extensions |
| if key == key_ { |
| values.extend_from_slice(types); |
| continue; |
| } |
| } |
| |
| map_entries.push((key, types.into())); |
| } |
| |
| for (key, values) in map_entries { |
| forward_map.entry( |
| UniCase::new(key), |
| &format!("&{:?}", values), |
| ); |
| } |
| |
| writeln!( |
| out, |
| "static MIME_TYPES: phf::Map<UniCase<&'static str>, &'static [&'static str]> = \n{};", |
| forward_map.build() |
| ) |
| .unwrap(); |
| } |
| |
| // Build reverse mappings (mime type -> ext) |
| #[cfg(all(feature = "phf", feature = "rev-mappings"))] |
| fn build_rev_map<W: Write>(out: &mut W) { |
| use phf_codegen::Map as PhfMap; |
| |
| let dyn_map = get_rev_mappings(); |
| |
| let mut rev_map = PhfMap::new(); |
| rev_map.phf_path(PHF_PATH); |
| |
| let mut exts = Vec::new(); |
| |
| for (top, subs) in dyn_map { |
| let top_start = exts.len(); |
| |
| let mut sub_map = PhfMap::new(); |
| sub_map.phf_path(PHF_PATH); |
| |
| for (sub, sub_exts) in subs { |
| let sub_start = exts.len(); |
| exts.extend(sub_exts); |
| let sub_end = exts.len(); |
| |
| sub_map.entry(sub, &format!("({}, {})", sub_start, sub_end)); |
| } |
| |
| let top_end = exts.len(); |
| |
| rev_map.entry( |
| top, |
| &format!( |
| "TopLevelExts {{ start: {}, end: {}, subs: {} }}", |
| top_start, top_end, sub_map.build() |
| ), |
| ); |
| } |
| |
| writeln!( |
| out, |
| "static REV_MAPPINGS: phf::Map<UniCase<&'static str>, TopLevelExts> = \n{};", |
| rev_map.build() |
| ).unwrap(); |
| |
| writeln!(out, "const EXTS: &'static [&'static str] = &{:?};", exts).unwrap(); |
| } |
| |
| #[cfg(all(not(feature = "phf"), feature = "rev-mappings"))] |
| fn build_rev_map<W: Write>(out: &mut W) { |
| use std::fmt::Write as _; |
| |
| macro_rules! unicase_const { |
| ($s:expr) => ({ |
| format_args!("{}({:?})", (if $s.is_ascii() { |
| "UniCase::ascii" |
| } else { |
| "UniCase::unicode" |
| }), $s) |
| }) |
| } |
| |
| let dyn_map = get_rev_mappings(); |
| |
| write!(out, "static REV_MAPPINGS: &'static [(UniCase<&'static str>, TopLevelExts)] = &[").unwrap(); |
| |
| let mut exts = Vec::new(); |
| |
| for (top, subs) in dyn_map { |
| let top_start = exts.len(); |
| |
| let mut sub_map = String::new(); |
| |
| for (sub, sub_exts) in subs { |
| let sub_start = exts.len(); |
| exts.extend(sub_exts); |
| let sub_end = exts.len(); |
| |
| write!( |
| sub_map, |
| "({}, ({}, {})),", |
| unicase_const!(sub), sub_start, sub_end |
| ).unwrap(); |
| } |
| |
| let top_end = exts.len(); |
| |
| write!( |
| out, |
| "({}, TopLevelExts {{ start: {}, end: {}, subs: &[{}] }}),", |
| unicase_const!(top), top_start, top_end, sub_map |
| ).unwrap(); |
| } |
| |
| writeln!(out, "];").unwrap(); |
| |
| writeln!(out, "const EXTS: &'static [&'static str] = &{:?};", exts).unwrap(); |
| } |
| |
| #[cfg(feature = "rev-mappings")] |
| fn get_rev_mappings( |
| ) -> BTreeMap<UniCase<&'static str>, BTreeMap<UniCase<&'static str>, Vec<&'static str>>> { |
| // First, collect all the mime type -> ext mappings) |
| let mut dyn_map = BTreeMap::new(); |
| for &(key, types) in MIME_TYPES { |
| for val in types { |
| let (top, sub) = split_mime(val); |
| dyn_map |
| .entry(UniCase::new(top)) |
| .or_insert_with(BTreeMap::new) |
| .entry(UniCase::new(sub)) |
| .or_insert_with(Vec::new) |
| .push(key); |
| } |
| } |
| dyn_map |
| } |
| |
| fn split_mime(mime: &str) -> (&str, &str) { |
| let split_idx = mime.find('/').unwrap(); |
| (&mime[..split_idx], &mime[split_idx + 1..]) |
| } |