• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::any::{Any, TypeId};
2 use std::borrow::Borrow;
3 use std::cell::RefCell;
4 use std::cmp::Ordering;
5 use std::collections::HashMap;
6 use std::fmt;
7 use std::hash::{Hash, Hasher};
8 use std::marker::PhantomData;
9 use std::mem;
10 use std::ops::Deref;
11 use std::path::PathBuf;
12 use std::sync::Mutex;
13 
14 // FIXME: replace with std::lazy after it gets stabilized and reaches beta
15 use once_cell::sync::Lazy;
16 
17 use crate::builder::Step;
18 
19 pub struct Interned<T>(usize, PhantomData<*const T>);
20 
21 impl<T: Internable + Default> Default for Interned<T> {
default() -> Self22     fn default() -> Self {
23         T::default().intern()
24     }
25 }
26 
27 impl<T> Copy for Interned<T> {}
28 impl<T> Clone for Interned<T> {
clone(&self) -> Interned<T>29     fn clone(&self) -> Interned<T> {
30         *self
31     }
32 }
33 
34 impl<T> PartialEq for Interned<T> {
eq(&self, other: &Self) -> bool35     fn eq(&self, other: &Self) -> bool {
36         self.0 == other.0
37     }
38 }
39 impl<T> Eq for Interned<T> {}
40 
41 impl PartialEq<str> for Interned<String> {
eq(&self, other: &str) -> bool42     fn eq(&self, other: &str) -> bool {
43         *self == other
44     }
45 }
46 impl<'a> PartialEq<&'a str> for Interned<String> {
eq(&self, other: &&str) -> bool47     fn eq(&self, other: &&str) -> bool {
48         **self == **other
49     }
50 }
51 impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
eq(&self, other: &&Self) -> bool52     fn eq(&self, other: &&Self) -> bool {
53         self.0 == other.0
54     }
55 }
56 impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
eq(&self, other: &Interned<T>) -> bool57     fn eq(&self, other: &Interned<T>) -> bool {
58         self.0 == other.0
59     }
60 }
61 
62 unsafe impl<T> Send for Interned<T> {}
63 unsafe impl<T> Sync for Interned<T> {}
64 
65 impl fmt::Display for Interned<String> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result66     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67         let s: &str = &*self;
68         f.write_str(s)
69     }
70 }
71 
72 impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
73 where
74     Self: Deref<Target = U>,
75 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result76     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77         let s: &U = &*self;
78         f.write_fmt(format_args!("{:?}", s))
79     }
80 }
81 
82 impl<T: Internable + Hash> Hash for Interned<T> {
hash<H: Hasher>(&self, state: &mut H)83     fn hash<H: Hasher>(&self, state: &mut H) {
84         let l = T::intern_cache().lock().unwrap();
85         l.get(*self).hash(state)
86     }
87 }
88 
89 impl<T: Internable + Deref> Deref for Interned<T> {
90     type Target = T::Target;
deref(&self) -> &Self::Target91     fn deref(&self) -> &Self::Target {
92         let l = T::intern_cache().lock().unwrap();
93         unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) }
94     }
95 }
96 
97 impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
as_ref(&self) -> &U98     fn as_ref(&self) -> &U {
99         let l = T::intern_cache().lock().unwrap();
100         unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) }
101     }
102 }
103 
104 impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
partial_cmp(&self, other: &Self) -> Option<Ordering>105     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
106         let l = T::intern_cache().lock().unwrap();
107         l.get(*self).partial_cmp(l.get(*other))
108     }
109 }
110 
111 impl<T: Internable + Ord> Ord for Interned<T> {
cmp(&self, other: &Self) -> Ordering112     fn cmp(&self, other: &Self) -> Ordering {
113         let l = T::intern_cache().lock().unwrap();
114         l.get(*self).cmp(l.get(*other))
115     }
116 }
117 
118 struct TyIntern<T: Clone + Eq> {
119     items: Vec<T>,
120     set: HashMap<T, Interned<T>>,
121 }
122 
123 impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
default() -> Self124     fn default() -> Self {
125         TyIntern { items: Vec::new(), set: Default::default() }
126     }
127 }
128 
129 impl<T: Hash + Clone + Eq> TyIntern<T> {
intern_borrow<B>(&mut self, item: &B) -> Interned<T> where B: Eq + Hash + ToOwned<Owned = T> + ?Sized, T: Borrow<B>,130     fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
131     where
132         B: Eq + Hash + ToOwned<Owned = T> + ?Sized,
133         T: Borrow<B>,
134     {
135         if let Some(i) = self.set.get(&item) {
136             return *i;
137         }
138         let item = item.to_owned();
139         let interned = Interned(self.items.len(), PhantomData::<*const T>);
140         self.set.insert(item.clone(), interned);
141         self.items.push(item);
142         interned
143     }
144 
intern(&mut self, item: T) -> Interned<T>145     fn intern(&mut self, item: T) -> Interned<T> {
146         if let Some(i) = self.set.get(&item) {
147             return *i;
148         }
149         let interned = Interned(self.items.len(), PhantomData::<*const T>);
150         self.set.insert(item.clone(), interned);
151         self.items.push(item);
152         interned
153     }
154 
get(&self, i: Interned<T>) -> &T155     fn get(&self, i: Interned<T>) -> &T {
156         &self.items[i.0]
157     }
158 }
159 
160 #[derive(Default)]
161 pub struct Interner {
162     strs: Mutex<TyIntern<String>>,
163     paths: Mutex<TyIntern<PathBuf>>,
164     lists: Mutex<TyIntern<Vec<String>>>,
165 }
166 
167 trait Internable: Clone + Eq + Hash + 'static {
intern_cache() -> &'static Mutex<TyIntern<Self>>168     fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
169 
intern(self) -> Interned<Self>170     fn intern(self) -> Interned<Self> {
171         Self::intern_cache().lock().unwrap().intern(self)
172     }
173 }
174 
175 impl Internable for String {
intern_cache() -> &'static Mutex<TyIntern<Self>>176     fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
177         &INTERNER.strs
178     }
179 }
180 
181 impl Internable for PathBuf {
intern_cache() -> &'static Mutex<TyIntern<Self>>182     fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
183         &INTERNER.paths
184     }
185 }
186 
187 impl Internable for Vec<String> {
intern_cache() -> &'static Mutex<TyIntern<Self>>188     fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
189         &INTERNER.lists
190     }
191 }
192 
193 impl Interner {
intern_str(&self, s: &str) -> Interned<String>194     pub fn intern_str(&self, s: &str) -> Interned<String> {
195         self.strs.lock().unwrap().intern_borrow(s)
196     }
intern_string(&self, s: String) -> Interned<String>197     pub fn intern_string(&self, s: String) -> Interned<String> {
198         self.strs.lock().unwrap().intern(s)
199     }
200 
intern_path(&self, s: PathBuf) -> Interned<PathBuf>201     pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
202         self.paths.lock().unwrap().intern(s)
203     }
204 
intern_list(&self, v: Vec<String>) -> Interned<Vec<String>>205     pub fn intern_list(&self, v: Vec<String>) -> Interned<Vec<String>> {
206         self.lists.lock().unwrap().intern(v)
207     }
208 }
209 
210 pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
211 
212 /// This is essentially a `HashMap` which allows storing any type in its input and
213 /// any type in its output. It is a write-once cache; values are never evicted,
214 /// which means that references to the value can safely be returned from the
215 /// `get()` method.
216 #[derive(Debug)]
217 pub struct Cache(
218     RefCell<
219         HashMap<
220             TypeId,
221             Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>>
222         >,
223     >,
224 );
225 
226 impl Cache {
new() -> Cache227     pub fn new() -> Cache {
228         Cache(RefCell::new(HashMap::new()))
229     }
230 
put<S: Step>(&self, step: S, value: S::Output)231     pub fn put<S: Step>(&self, step: S, value: S::Output) {
232         let mut cache = self.0.borrow_mut();
233         let type_id = TypeId::of::<S>();
234         let stepcache = cache
235             .entry(type_id)
236             .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
237             .downcast_mut::<HashMap<S, S::Output>>()
238             .expect("invalid type mapped");
239         assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
240         stepcache.insert(step, value);
241     }
242 
get<S: Step>(&self, step: &S) -> Option<S::Output>243     pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
244         let mut cache = self.0.borrow_mut();
245         let type_id = TypeId::of::<S>();
246         let stepcache = cache
247             .entry(type_id)
248             .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
249             .downcast_mut::<HashMap<S, S::Output>>()
250             .expect("invalid type mapped");
251         stepcache.get(step).cloned()
252     }
253 }
254 
255 #[cfg(test)]
256 impl Cache {
all<S: Ord + Clone + Step>(&mut self) -> Vec<(S, S::Output)>257     pub fn all<S: Ord + Clone + Step>(&mut self) -> Vec<(S, S::Output)> {
258         let cache = self.0.get_mut();
259         let type_id = TypeId::of::<S>();
260         let mut v = cache
261             .remove(&type_id)
262             .map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
263             .map(|m| m.into_iter().collect::<Vec<_>>())
264             .unwrap_or_default();
265         v.sort_by_key(|(s, _)| s.clone());
266         v
267     }
268 
contains<S: Step>(&self) -> bool269     pub fn contains<S: Step>(&self) -> bool {
270         self.0.borrow().contains_key(&TypeId::of::<S>())
271     }
272 }
273