Skip to content

Commit ea65dc2

Browse files
author
bors-servo
authored
Auto merge of #178 - servo:static-sets, r=Manishearth
Make Atom generic over the set of static strings The new `string_cache_codegen` crate is intended to be used by downstream users in their build scripts. Provided a list of static strings, it generates code that defines: - A type alias for `Atom<_>` with the type parameter set, - A macro like the former `atom!` macro. Based on #136, original work by @aidanhs. Fixes #22, fixes #136, closes #83. r? @nox <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/string-cache/178) <!-- Reviewable:end -->
2 parents 7379d87 + 4528d77 commit ea65dc2

File tree

14 files changed

+400
-1641
lines changed

14 files changed

+400
-1641
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ script:
1313
- cargo test --features log-events
1414
- "if [ $TRAVIS_RUST_VERSION = nightly ]; then cargo test --features unstable; fi"
1515
- cargo test --features heapsize
16+
- "cd string-cache-codegen/ && cargo build && cd .."
1617
- "cd examples/event-log/ && cargo build && cd ../.."
1718
- "cd examples/summarize-events/ && cargo build && cd ../.."
1819
notifications:

Cargo.toml

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
[package]
22

33
name = "string_cache"
4-
version = "0.2.30"
4+
version = "0.3.0" # Also update README.md when making a semver-breaking change
55
authors = [ "The Servo Project Developers" ]
66
description = "A string interning library for Rust, developed as part of the Servo project."
77
license = "MIT / Apache-2.0"
88
repository = "https://github.com/servo/string-cache"
9-
documentation = "http://doc.servo.org/string_cache/"
9+
documentation = "https://docs.rs/string_cache/"
1010
build = "build.rs"
1111

12+
# Do not `exclude` ./string-cache-codegen because we want to include
13+
# ./string-cache-codegen/shared.rs, and `include` is a pain to use
14+
# (It has to be exhaustive.)
15+
# This means that packages for this crate include some unused files,
16+
# but they’re not too big so that shouldn’t be a problem.
17+
1218
[lib]
1319
name = "string_cache"
1420

@@ -26,21 +32,14 @@ heap_size = ["heapsize"]
2632

2733
[dependencies]
2834
lazy_static = "0.2"
29-
serde = ">=0.6, <0.9"
35+
serde = "0.8"
3036
phf_shared = "0.7.4"
3137
debug_unreachable = "0.1.1"
38+
rustc-serialize = { version = "0.3", optional = true }
39+
heapsize = { version = "0.3", optional = true }
3240

3341
[dev-dependencies]
3442
rand = "0.3"
3543

36-
[dependencies.rustc-serialize]
37-
version = "0.3"
38-
optional = true
39-
40-
[dependencies.heapsize]
41-
version = ">=0.1.1, <0.4"
42-
optional = true
43-
4444
[build-dependencies]
45-
phf_generator = "0.7.4"
46-
phf_shared = "0.7.4"
45+
string_cache_codegen = { version = "0.3", path = "./string-cache-codegen" }

README.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,77 @@
22

33
[![Build Status](https://travis-ci.org/servo/string-cache.svg?branch=master)](https://travis-ci.org/servo/string-cache)
44

5-
[Documentation](http://doc.servo.org/string_cache/)
5+
[Documentation](https://docs.rs/string_cache/)
66

77
A string interning library for Rust, developed as part of the [Servo](https://github.com/servo/servo) project.
8+
9+
## Simple usage
10+
11+
In `Cargo.toml`:
12+
13+
```toml
14+
[dependencies]
15+
string_cache = "0.3"
16+
```
17+
18+
In `lib.rs`:
19+
20+
```rust
21+
extern crate string_cache;
22+
use string_cache::DefaultAtom as Atom;
23+
```
24+
25+
## With static atoms
26+
27+
In `Cargo.toml`:
28+
29+
```toml
30+
[package]
31+
build = "build.rs"
32+
33+
[dependencies]
34+
string_cache = "0.3"
35+
36+
[build-dependencies]
37+
string_cache_codegen = "0.3"
38+
```
39+
40+
In `build.rs`:
41+
42+
```rust
43+
extern crate string_cache_codegen;
44+
45+
use std::env;
46+
use std::path::Path;
47+
48+
fn main() {
49+
string_cache_codegen::AtomType::new("foo::FooAtom", "foo_atom!")
50+
.atoms(&["foo", "bar"])
51+
.write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("foo_atom.rs"))
52+
.unwrap()
53+
}
54+
```
55+
56+
In `lib.rs`:
57+
58+
```rust
59+
extern crate string_cache;
60+
61+
mod foo {
62+
include!(concat!(env!("OUT_DIR"), "/foo_atom.rs"));
63+
}
64+
```
65+
66+
The generated code will define a `FooAtom` type and a `foo_atom!` macro.
67+
The macro can be used in expression or patterns, with strings listed in `build.rs`.
68+
For example:
69+
70+
```rust
71+
fn compute_something(input: &foo::FooAtom) -> u32 {
72+
match *input {
73+
foo_atom!("foo") => 1,
74+
foo_atom!("bar") => 2,
75+
_ => 3,
76+
}
77+
}
78+
```

build.rs

Lines changed: 7 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,13 @@
1-
extern crate phf_shared;
2-
extern crate phf_generator;
3-
4-
#[path = "src/shared.rs"] #[allow(dead_code)] mod shared;
5-
#[path = "src/static_atom_list.rs"] mod static_atom_list;
1+
extern crate string_cache_codegen;
62

73
use std::env;
8-
use std::fs::File;
9-
use std::io::{BufWriter, Write};
10-
use std::mem;
114
use std::path::Path;
12-
use std::slice;
135

146
fn main() {
15-
let hash_state = generate();
16-
write_static_atom_set(&hash_state);
17-
write_atom_macro(&hash_state);
18-
}
19-
20-
fn generate() -> phf_generator::HashState {
21-
let mut set = std::collections::HashSet::new();
22-
for atom in static_atom_list::ATOMS {
23-
if !set.insert(atom) {
24-
panic!("duplicate static atom `{:?}`", atom);
25-
}
26-
}
27-
phf_generator::generate_hash(static_atom_list::ATOMS)
28-
}
29-
30-
fn write_static_atom_set(hash_state: &phf_generator::HashState) {
31-
let path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("static_atom_set.rs");
32-
let mut file = BufWriter::new(File::create(&path).unwrap());
33-
macro_rules! w {
34-
($($arg: expr),+) => { (writeln!(&mut file, $($arg),+).unwrap()) }
35-
}
36-
w!("pub static STATIC_ATOM_SET: StaticAtomSet = StaticAtomSet {{");
37-
w!(" key: {},", hash_state.key);
38-
w!(" disps: &[");
39-
for &(d1, d2) in &hash_state.disps {
40-
w!(" ({}, {}),", d1, d2);
41-
}
42-
w!(" ],");
43-
w!(" atoms: &[");
44-
for &idx in &hash_state.map {
45-
w!(" {:?},", static_atom_list::ATOMS[idx]);
46-
}
47-
w!(" ],");
48-
w!("}};");
49-
}
50-
51-
fn write_atom_macro(hash_state: &phf_generator::HashState) {
52-
let set = shared::StaticAtomSet {
53-
key: hash_state.key,
54-
disps: leak(hash_state.disps.clone()),
55-
atoms: leak(hash_state.map.iter().map(|&idx| static_atom_list::ATOMS[idx]).collect()),
56-
};
57-
58-
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("atom_macro.rs");
59-
let mut file = BufWriter::new(File::create(&path).unwrap());
60-
writeln!(file, r"#[macro_export]").unwrap();
61-
writeln!(file, r"macro_rules! atom {{").unwrap();
62-
for &s in set.iter() {
63-
let data = shared::pack_static(set.get_index_or_hash(s).unwrap() as u32);
64-
writeln!(file, r"({:?}) => {{ $crate::Atom {{ unsafe_data: 0x{:x} }} }};", s, data).unwrap();
65-
}
66-
writeln!(file, r"}}").unwrap();
67-
}
68-
69-
fn leak<T>(v: Vec<T>) -> &'static [T] {
70-
let slice = unsafe { slice::from_raw_parts(v.as_ptr(), v.len()) };
71-
mem::forget(v);
72-
slice
7+
string_cache_codegen::AtomType::new("atom::tests::TestAtom", "test_atom!")
8+
.atoms(&[
9+
"a", "b", "address", "area", "body", "font-weight", "br", "html", "head", "id",
10+
])
11+
.write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("test_atom.rs"))
12+
.unwrap()
7313
}

examples/event-log/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
extern crate string_cache;
1111

12-
use string_cache::Atom;
12+
use string_cache::DefaultAtom as Atom;
1313
use string_cache::event;
1414

1515
use std::io;

examples/summarize-events/src/main.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ extern crate string_cache;
1212
extern crate rustc_serialize;
1313
extern crate phf_shared;
1414

15-
#[path = "../../../src/shared.rs"]
15+
#[path = "../../../string-cache-codegen/shared.rs"]
1616
#[allow(dead_code)]
1717
mod shared;
1818

19-
use string_cache::Atom;
19+
use string_cache::DefaultAtom as Atom;
2020

2121
use std::{env, cmp};
2222
use std::collections::hash_map::{HashMap, Entry};
23+
use std::marker::PhantomData;
2324
use std::path::Path;
2425

2526
#[derive(RustcDecodable, Debug)]
@@ -88,7 +89,7 @@ fn main() {
8889

8990
// FIXME: We really shouldn't be allowed to do this. It's a memory-safety
9091
// hazard; the field is only public for the atom!() macro.
91-
_ => Atom { unsafe_data: ev.id }.to_string(),
92+
_ => Atom { unsafe_data: ev.id, phantom: PhantomData }.to_string(),
9293
};
9394

9495
match summary.entry(string) {

0 commit comments

Comments
 (0)