Skip to content

Commit 4d2419d

Browse files
committed
Add string-cache-codegen crate
1 parent 3a97af6 commit 4d2419d

File tree

8 files changed

+187
-0
lines changed

8 files changed

+187
-0
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ license = "MIT / Apache-2.0"
88
repository = "https://github.com/servo/string-cache"
99
documentation = "http://doc.servo.org/string_cache/"
1010
build = "build.rs"
11+
exclude = ["string-cache-codegen/**/*"]
1112

1213
[lib]
1314
name = "string_cache"

string-cache-codegen/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
target
2+
Cargo.lock
3+
*.swp

string-cache-codegen/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
3+
name = "string_cache_codegen"
4+
version = "0.2.11"
5+
authors = [ "The Servo Project Developers" ]
6+
description = "A codegen library for string-cache, developed as part of the Servo project."
7+
license = "MIT / Apache-2.0"
8+
repository = "https://github.com/servo/string-cache"
9+
documentation = "http://doc.servo.org/string_cache_codegen/"
10+
11+
[lib]
12+
name = "string_cache_codegen"
13+
14+
[dependencies]
15+
phf_codegen = "0.7.4"

string-cache-codegen/README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# string-cache-codegen
2+
3+
Example usage:
4+
5+
```
6+
extern crate string_cache_codegen;
7+
8+
use std::env;
9+
use std::fs::File;
10+
use std::io::BufWriter;
11+
use std::path::Path;
12+
13+
fn main() {
14+
let file = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
15+
let mut file = BufWriter::new(File::create(&file).unwrap());
16+
17+
string_cache_codegen::AtomSetBuilder::new()
18+
.atom("a")
19+
.atom("b")
20+
.atom("c")
21+
.build(&mut file, "Alphabet", "ALPHABET_ATOMS", "alphabet");
22+
}
23+
```
24+
25+
Then just add `include!(concat!(env!("OUT_DIR"), "/codegen.rs"));` to the root
26+
of your crate.

string-cache-codegen/src/lib.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
extern crate phf_codegen;
2+
3+
use std::io::Write;
4+
5+
/// A builder for a static atom set and relevant macros
6+
pub struct AtomSetBuilder {
7+
atoms: Vec<&'static str>,
8+
}
9+
10+
impl AtomSetBuilder {
11+
/// Constructs a new static atom set builder
12+
pub fn new() -> AtomSetBuilder {
13+
AtomSetBuilder {
14+
atoms: vec![],
15+
}
16+
}
17+
18+
/// Adds an atom to the builder
19+
pub fn atom(&mut self, s: &'static str) -> &mut AtomSetBuilder {
20+
self.atoms.push(s);
21+
self
22+
}
23+
24+
/// Adds multiple atoms to the builder
25+
pub fn atoms(&mut self, ss: &[&'static str]) -> &mut AtomSetBuilder {
26+
// `self.atoms.extend_from_slice(ss);` in newer rust
27+
for s in ss {
28+
self.atoms.push(s);
29+
}
30+
self
31+
}
32+
33+
/// Constructs a new atom type with the name `atom_type_name`, a static atom
34+
/// set with the name `static_set_name` and a macro with the name
35+
/// `macro_name` for converting strings to static atoms at compile time.
36+
/// Using the macro requires you to include the generated file in the root
37+
/// of your crate, likely with the `include!` macro.
38+
pub fn build<W>(&self, w: &mut W, atom_type_name: &str, static_set_name: &str, macro_name: &str) where W: Write {
39+
if self.atoms.is_empty() {
40+
panic!("must have more than one atom of a kind");
41+
}
42+
self.build_kind_definition(w, static_set_name, atom_type_name);
43+
self.build_static_atom_set(w, static_set_name);
44+
self.build_atom_macro(w, macro_name, atom_type_name);
45+
}
46+
47+
fn build_kind_definition<W>(&self, w: &mut W, static_set_name: &str, atom_type_name: &str) where W: Write {
48+
writeln!(w, "#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]").unwrap();
49+
writeln!(w, "pub enum {}Kind {{}}", atom_type_name).unwrap();
50+
writeln!(w, "
51+
impl ::string_cache::atom::Kind for {atom_type_name}Kind {{
52+
#[inline]
53+
fn get_index_or_hash(s: &str) -> Result<u32, u64> {{
54+
match {static_set_name}.get_index(s) {{
55+
Some(i) => Ok(i as u32),
56+
None => Err(::string_cache::shared::dynamic_hash(s)),
57+
}}
58+
}}
59+
60+
#[inline]
61+
fn index(i: u32) -> Option<&'static str> {{
62+
{static_set_name}.index(i as usize).map(|&s| s)
63+
}}
64+
}}
65+
", atom_type_name=atom_type_name, static_set_name=static_set_name).unwrap();
66+
writeln!(w, "pub type {} = ::string_cache::atom::BaseAtom<{}Kind>;", atom_type_name, atom_type_name).unwrap();
67+
}
68+
69+
fn build_static_atom_set<W>(&self, w: &mut W, static_set_name: &str) where W: Write {
70+
writeln!(w, "pub static {}: ::string_cache::shared::phf::OrderedSet<&'static str> = ", static_set_name).unwrap();
71+
write!(w, "::string_cache::shared::phf::OrderedSet {{ map: ::string_cache::shared").unwrap();
72+
let mut builder = phf_codegen::OrderedMap::new();
73+
for &atom in &self.atoms {
74+
builder.entry(atom, "()");
75+
}
76+
builder.build(w).unwrap();
77+
writeln!(w, "}};").unwrap();
78+
}
79+
80+
fn build_atom_macro<W>(&self, w: &mut W, macro_name: &str, atom_type_name: &str) where W: Write {
81+
writeln!(w, r"#[macro_export]").unwrap();
82+
writeln!(w, r"macro_rules! {} {{", macro_name).unwrap();
83+
for (i, s) in self.atoms.iter().enumerate() {
84+
let data = pack_static(i as u32);
85+
writeln!(w, r"({:?}) => {{ $crate::{} {{ data: 0x{:x}, kind: ::std::marker::PhantomData }} }};", s, atom_type_name, data).unwrap();
86+
}
87+
writeln!(w, r"}}").unwrap();
88+
}
89+
}
90+
91+
// Duplicated from string_cache::shared to lift dependency on string_cache
92+
const STATIC_TAG: u8 = 0b_10;
93+
const STATIC_SHIFT_BITS: usize = 32;
94+
fn pack_static(n: u32) -> u64 {
95+
(STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS)
96+
}

string-cache-codegen/test/Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "string_cache_codegen_test"
3+
authors = [ "The Servo Project Developers" ]
4+
version = "0.0.0"
5+
build = "build.rs"
6+
7+
[build-dependencies.string_cache_codegen]
8+
path = ".."
9+
version = "0.2.5"
10+
11+
[dependencies.string_cache]
12+
version = "0.2.5"

string-cache-codegen/test/build.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
extern crate string_cache_codegen;
2+
3+
use std::env;
4+
use std::fs::File;
5+
use std::io::BufWriter;
6+
use std::path::Path;
7+
8+
fn main() {
9+
let file = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
10+
let mut file = BufWriter::new(File::create(&file).unwrap());
11+
12+
string_cache_codegen::AtomSetBuilder::new()
13+
.atom("a")
14+
.atom("b")
15+
.atom("c")
16+
.build(&mut file, "Alphabet", "ALPHABET_ATOMS", "alphabet");
17+
}

string-cache-codegen/test/src/lib.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
extern crate string_cache;
2+
3+
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
4+
5+
#[cfg(test)]
6+
mod test {
7+
use super::{ALPHABET_ATOMS, Alphabet};
8+
#[test]
9+
fn static_atom_set() {
10+
let a: Alphabet = alphabet!("a");
11+
assert!(&*a == "a");
12+
assert!(&*alphabet!("b") == "b");
13+
assert!(ALPHABET_ATOMS.contains("c"));
14+
assert!(!ALPHABET_ATOMS.contains("d"));
15+
assert!(ALPHABET_ATOMS.len() == 3);
16+
}
17+
}

0 commit comments

Comments
 (0)