]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/cache.rs
Rollup merge of #44533 - nrc:rustfmt-submod, r=alexcrichton
[rust.git] / src / bootstrap / cache.rs
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.
4 //
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.
10
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;
16 use std::ffi::OsStr;
17 use std::fmt;
18 use std::hash::{Hash, Hasher};
19 use std::marker::PhantomData;
20 use std::mem;
21 use std::ops::Deref;
22 use std::path::{Path, PathBuf};
23 use std::sync::Mutex;
24
25 use builder::Step;
26
27 pub struct Interned<T>(usize, PhantomData<*const T>);
28
29 impl Default for Interned<String> {
30     fn default() -> Self {
31         INTERNER.intern_string(String::default())
32     }
33 }
34
35 impl Default for Interned<PathBuf> {
36     fn default() -> Self {
37         INTERNER.intern_path(PathBuf::default())
38     }
39 }
40
41 impl<T> Copy for Interned<T> {}
42 impl<T> Clone for Interned<T> {
43     fn clone(&self) -> Interned<T> {
44         *self
45     }
46 }
47
48 impl<T> PartialEq for Interned<T> {
49     fn eq(&self, other: &Self) -> bool {
50         self.0 == other.0
51     }
52 }
53 impl<T> Eq for Interned<T> {}
54
55 impl PartialEq<str> for Interned<String> {
56     fn eq(&self, other: &str) -> bool {
57        *self == other
58     }
59 }
60 impl<'a> PartialEq<&'a str> for Interned<String> {
61     fn eq(&self, other: &&str) -> bool {
62         **self == **other
63     }
64 }
65 impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
66     fn eq(&self, other: &&Self) -> bool {
67         self.0 == other.0
68     }
69 }
70 impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
71     fn eq(&self, other: &Interned<T>) -> bool {
72         self.0 == other.0
73     }
74 }
75
76 unsafe impl<T> Send for Interned<T> {}
77 unsafe impl<T> Sync for Interned<T> {}
78
79 impl fmt::Display for Interned<String> {
80     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81         let s: &str = &*self;
82         f.write_str(s)
83     }
84 }
85
86 impl fmt::Debug for Interned<String> {
87     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88         let s: &str = &*self;
89         f.write_fmt(format_args!("{:?}", s))
90     }
91 }
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))
96     }
97 }
98
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)
103     }
104 }
105
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)
110     }
111 }
112
113 impl Deref for Interned<String> {
114     type Target = str;
115     fn deref(&self) -> &'static str {
116         let l = INTERNER.strs.lock().unwrap();
117         unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
118     }
119 }
120
121 impl Deref for Interned<PathBuf> {
122     type Target = Path;
123     fn deref(&self) -> &'static Path {
124         let l = INTERNER.paths.lock().unwrap();
125         unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
126     }
127 }
128
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)) }
133     }
134 }
135
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()) }
140     }
141 }
142
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()) }
147     }
148 }
149
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()) }
154     }
155 }
156
157
158 struct TyIntern<T> {
159     items: Vec<T>,
160     set: HashMap<T, Interned<T>>,
161 }
162
163 impl<T: Hash + Clone + Eq> TyIntern<T> {
164     fn new() -> TyIntern<T> {
165         TyIntern {
166             items: Vec::new(),
167             set: HashMap::new(),
168         }
169     }
170
171     fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
172     where
173         B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
174         T: Borrow<B>,
175     {
176         if let Some(i) = self.set.get(&item) {
177             return *i;
178         }
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);
183         interned
184     }
185
186     fn intern(&mut self, item: T) -> Interned<T> {
187         if let Some(i) = self.set.get(&item) {
188             return *i;
189         }
190         let interned =  Interned(self.items.len(), PhantomData::<*const T>);
191         self.set.insert(item.clone(), interned);
192         self.items.push(item);
193         interned
194     }
195
196     fn get(&self, i: Interned<T>) -> &T {
197         &self.items[i.0]
198     }
199 }
200
201 pub struct Interner {
202     strs: Mutex<TyIntern<String>>,
203     paths: Mutex<TyIntern<PathBuf>>,
204 }
205
206 impl Interner {
207     fn new() -> Interner {
208         Interner {
209             strs: Mutex::new(TyIntern::new()),
210             paths: Mutex::new(TyIntern::new()),
211         }
212     }
213
214     pub fn intern_str(&self, s: &str) -> Interned<String> {
215         self.strs.lock().unwrap().intern_borrow(s)
216     }
217     pub fn intern_string(&self, s: String) -> Interned<String> {
218         self.strs.lock().unwrap().intern(s)
219     }
220
221     pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
222         self.paths.lock().unwrap().intern(s)
223     }
224 }
225
226 lazy_static! {
227     pub static ref INTERNER: Interner = Interner::new();
228 }
229
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
233 /// get() method.
234 #[derive(Debug)]
235 pub struct Cache(
236     RefCell<HashMap<
237         TypeId,
238         Box<Any>, // actually a HashMap<Step, Interned<Step::Output>>
239     >>
240 );
241
242 impl Cache {
243     pub fn new() -> Cache {
244         Cache(RefCell::new(HashMap::new()))
245     }
246
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);
256     }
257
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()
266     }
267 }