1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use std::any::{Any, TypeId};
12 use std::borrow::Borrow;
13 use std::cell::RefCell;
14 use std::collections::HashMap;
15 use std::convert::AsRef;
18 use std::hash::{Hash, Hasher};
19 use std::marker::PhantomData;
22 use std::path::{Path, PathBuf};
27 pub struct Interned<T>(usize, PhantomData<*const T>);
29 impl Default for Interned<String> {
30 fn default() -> Self {
31 INTERNER.intern_string(String::default())
35 impl Default for Interned<PathBuf> {
36 fn default() -> Self {
37 INTERNER.intern_path(PathBuf::default())
41 impl<T> Copy for Interned<T> {}
42 impl<T> Clone for Interned<T> {
43 fn clone(&self) -> Interned<T> {
48 impl<T> PartialEq for Interned<T> {
49 fn eq(&self, other: &Self) -> bool {
53 impl<T> Eq for Interned<T> {}
55 impl PartialEq<str> for Interned<String> {
56 fn eq(&self, other: &str) -> bool {
60 impl<'a> PartialEq<&'a str> for Interned<String> {
61 fn eq(&self, other: &&str) -> bool {
65 impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
66 fn eq(&self, other: &&Self) -> bool {
70 impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
71 fn eq(&self, other: &Interned<T>) -> bool {
76 unsafe impl<T> Send for Interned<T> {}
77 unsafe impl<T> Sync for Interned<T> {}
79 impl fmt::Display for Interned<String> {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 impl fmt::Debug for Interned<String> {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 f.write_fmt(format_args!("{:?}", s))
92 impl fmt::Debug for Interned<PathBuf> {
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 let s: &Path = &*self;
95 f.write_fmt(format_args!("{:?}", s))
99 impl Hash for Interned<String> {
100 fn hash<H: Hasher>(&self, state: &mut H) {
101 let l = INTERNER.strs.lock().unwrap();
102 l.get(*self).hash(state)
106 impl Hash for Interned<PathBuf> {
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 let l = INTERNER.paths.lock().unwrap();
109 l.get(*self).hash(state)
113 impl Deref for Interned<String> {
115 fn deref(&self) -> &'static str {
116 let l = INTERNER.strs.lock().unwrap();
117 unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
121 impl Deref for Interned<PathBuf> {
123 fn deref(&self) -> &'static Path {
124 let l = INTERNER.paths.lock().unwrap();
125 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
129 impl AsRef<Path> for Interned<PathBuf> {
130 fn as_ref(&self) -> &'static Path {
131 let l = INTERNER.paths.lock().unwrap();
132 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
136 impl AsRef<Path> for Interned<String> {
137 fn as_ref(&self) -> &'static Path {
138 let l = INTERNER.strs.lock().unwrap();
139 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
143 impl AsRef<OsStr> for Interned<PathBuf> {
144 fn as_ref(&self) -> &'static OsStr {
145 let l = INTERNER.paths.lock().unwrap();
146 unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
150 impl AsRef<OsStr> for Interned<String> {
151 fn as_ref(&self) -> &'static OsStr {
152 let l = INTERNER.strs.lock().unwrap();
153 unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
160 set: HashMap<T, Interned<T>>,
163 impl<T: Hash + Clone + Eq> TyIntern<T> {
164 fn new() -> TyIntern<T> {
171 fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
173 B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
176 if let Some(i) = self.set.get(&item) {
179 let item = item.to_owned();
180 let interned = Interned(self.items.len(), PhantomData::<*const T>);
181 self.set.insert(item.clone(), interned);
182 self.items.push(item);
186 fn intern(&mut self, item: T) -> Interned<T> {
187 if let Some(i) = self.set.get(&item) {
190 let interned = Interned(self.items.len(), PhantomData::<*const T>);
191 self.set.insert(item.clone(), interned);
192 self.items.push(item);
196 fn get(&self, i: Interned<T>) -> &T {
201 pub struct Interner {
202 strs: Mutex<TyIntern<String>>,
203 paths: Mutex<TyIntern<PathBuf>>,
207 fn new() -> Interner {
209 strs: Mutex::new(TyIntern::new()),
210 paths: Mutex::new(TyIntern::new()),
214 pub fn intern_str(&self, s: &str) -> Interned<String> {
215 self.strs.lock().unwrap().intern_borrow(s)
217 pub fn intern_string(&self, s: String) -> Interned<String> {
218 self.strs.lock().unwrap().intern(s)
221 pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
222 self.paths.lock().unwrap().intern(s)
227 pub static ref INTERNER: Interner = Interner::new();
230 /// This is essentially a HashMap which allows storing any type in its input and
231 /// any type in its output. It is a write-once cache; values are never evicted,
232 /// which means that references to the value can safely be returned from the
238 Box<Any>, // actually a HashMap<Step, Interned<Step::Output>>
243 pub fn new() -> Cache {
244 Cache(RefCell::new(HashMap::new()))
247 pub fn put<S: Step>(&self, step: S, value: S::Output) {
248 let mut cache = self.0.borrow_mut();
249 let type_id = TypeId::of::<S>();
250 let stepcache = cache.entry(type_id)
251 .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
252 .downcast_mut::<HashMap<S, S::Output>>()
253 .expect("invalid type mapped");
254 assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
255 stepcache.insert(step, value);
258 pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
259 let mut cache = self.0.borrow_mut();
260 let type_id = TypeId::of::<S>();
261 let stepcache = cache.entry(type_id)
262 .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
263 .downcast_mut::<HashMap<S, S::Output>>()
264 .expect("invalid type mapped");
265 stepcache.get(step).cloned()