string_cache 0.2.13

A string interning library for Rust, developed as part of the Servo project.
Documentation
extern crate phf_shared;
extern crate phf_generator;

#[path = "src/shared.rs"] #[allow(dead_code)] mod shared;
#[path = "src/static_atom_list.rs"] mod static_atom_list;

use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::mem;
use std::path::Path;
use std::slice;

fn main() {
    let hash_state = generate();
    write_static_atom_set(&hash_state);
    write_atom_macro(&hash_state);
}

fn generate() -> phf_generator::HashState {
    let mut set = std::collections::HashSet::new();
    for atom in static_atom_list::ATOMS {
        if !set.insert(atom) {
            panic!("duplicate static atom `{:?}`", atom);
        }
    }
    phf_generator::generate_hash(static_atom_list::ATOMS)
}

fn write_static_atom_set(hash_state: &phf_generator::HashState) {
    let path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("static_atom_set.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());
    macro_rules! w {
        ($($arg: expr),+) => { (writeln!(&mut file, $($arg),+).unwrap()) }
    }
    w!("pub static STATIC_ATOM_SET: StaticAtomSet = StaticAtomSet {{");
    w!("    key: {},", hash_state.key);
    w!("    disps: &[");
    for &(d1, d2) in &hash_state.disps {
        w!("        ({}, {}),", d1, d2);
    }
    w!("    ],");
    w!("    atoms: &[");
    for &idx in &hash_state.map {
        w!("        {:?},", static_atom_list::ATOMS[idx]);
    }
    w!("    ],");
    w!("}};");
}

fn write_atom_macro(hash_state: &phf_generator::HashState) {
    let set = shared::StaticAtomSet {
        key: hash_state.key,
        disps: leak(hash_state.disps.clone()),
        atoms: leak(hash_state.map.iter().map(|&idx| static_atom_list::ATOMS[idx]).collect()),
    };

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("atom_macro.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());
    writeln!(file, r"#[macro_export]").unwrap();
    writeln!(file, r"macro_rules! atom {{").unwrap();
    for &s in set.iter() {
        let data = shared::pack_static(set.get_index_or_hash(s).unwrap() as u32);
        writeln!(file, r"({:?}) => {{ $crate::Atom {{ data: 0x{:x} }} }};", s, data).unwrap();
    }
    writeln!(file, r"}}").unwrap();
}

fn leak<T>(v: Vec<T>) -> &'static [T] {
    let slice = unsafe { slice::from_raw_parts(v.as_ptr(), v.len()) };
    mem::forget(v);
    slice
}