Skip to content

Commit 0566ade

Browse files
committed
Use generics for interned types rather than copy-pasting impls
This makes it much simpler to add new interned types, rather than having to add 4+ impl blocks for each type.
1 parent ee8e0bc commit 0566ade

File tree

1 file changed

+43
-69
lines changed

1 file changed

+43
-69
lines changed

src/bootstrap/cache.rs

+43-69
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ use std::cell::RefCell;
44
use std::cmp::{Ord, Ordering, PartialOrd};
55
use std::collections::HashMap;
66
use std::convert::AsRef;
7-
use std::ffi::OsStr;
87
use std::fmt;
98
use std::hash::{Hash, Hasher};
109
use std::marker::PhantomData;
1110
use std::mem;
1211
use std::ops::Deref;
13-
use std::path::{Path, PathBuf};
12+
use std::path::PathBuf;
1413
use std::sync::Mutex;
1514

1615
// FIXME: replace with std::lazy after it gets stabilized and reaches beta
@@ -20,15 +19,9 @@ use crate::builder::Step;
2019

2120
pub struct Interned<T>(usize, PhantomData<*const T>);
2221

23-
impl Default for Interned<String> {
22+
impl<T: Internable + Default> Default for Interned<T> {
2423
fn default() -> Self {
25-
INTERNER.intern_string(String::default())
26-
}
27-
}
28-
29-
impl Default for Interned<PathBuf> {
30-
fn default() -> Self {
31-
INTERNER.intern_path(PathBuf::default())
24+
T::default().intern()
3225
}
3326
}
3427

@@ -77,87 +70,48 @@ impl fmt::Display for Interned<String> {
7770
}
7871
}
7972

80-
impl fmt::Debug for Interned<String> {
81-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82-
let s: &str = &*self;
83-
f.write_fmt(format_args!("{:?}", s))
84-
}
85-
}
86-
impl fmt::Debug for Interned<PathBuf> {
73+
impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
74+
where
75+
Self: Deref<Target = U>,
76+
{
8777
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88-
let s: &Path = &*self;
78+
let s: &U = &*self;
8979
f.write_fmt(format_args!("{:?}", s))
9080
}
9181
}
9282

93-
impl Hash for Interned<String> {
83+
impl<T: Internable + Hash> Hash for Interned<T> {
9484
fn hash<H: Hasher>(&self, state: &mut H) {
95-
let l = INTERNER.strs.lock().unwrap();
85+
let l = T::intern_cache().lock().unwrap();
9686
l.get(*self).hash(state)
9787
}
9888
}
9989

100-
impl Hash for Interned<PathBuf> {
101-
fn hash<H: Hasher>(&self, state: &mut H) {
102-
let l = INTERNER.paths.lock().unwrap();
103-
l.get(*self).hash(state)
104-
}
105-
}
106-
107-
impl Deref for Interned<String> {
108-
type Target = str;
109-
fn deref(&self) -> &'static str {
110-
let l = INTERNER.strs.lock().unwrap();
111-
unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
112-
}
113-
}
114-
115-
impl Deref for Interned<PathBuf> {
116-
type Target = Path;
117-
fn deref(&self) -> &'static Path {
118-
let l = INTERNER.paths.lock().unwrap();
119-
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
120-
}
121-
}
122-
123-
impl AsRef<Path> for Interned<PathBuf> {
124-
fn as_ref(&self) -> &'static Path {
125-
let l = INTERNER.paths.lock().unwrap();
126-
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
127-
}
128-
}
129-
130-
impl AsRef<Path> for Interned<String> {
131-
fn as_ref(&self) -> &'static Path {
132-
let l = INTERNER.strs.lock().unwrap();
133-
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
90+
impl<T: Internable + Deref> Deref for Interned<T> {
91+
type Target = T::Target;
92+
fn deref(&self) -> &'static Self::Target {
93+
let l = T::intern_cache().lock().unwrap();
94+
unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
13495
}
13596
}
13697

137-
impl AsRef<OsStr> for Interned<PathBuf> {
138-
fn as_ref(&self) -> &'static OsStr {
139-
let l = INTERNER.paths.lock().unwrap();
140-
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
98+
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
99+
fn as_ref(&self) -> &'static U {
100+
let l = T::intern_cache().lock().unwrap();
101+
unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
141102
}
142103
}
143104

144-
impl AsRef<OsStr> for Interned<String> {
145-
fn as_ref(&self) -> &'static OsStr {
146-
let l = INTERNER.strs.lock().unwrap();
147-
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
148-
}
149-
}
150-
151-
impl PartialOrd<Interned<String>> for Interned<String> {
105+
impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
152106
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153-
let l = INTERNER.strs.lock().unwrap();
107+
let l = T::intern_cache().lock().unwrap();
154108
l.get(*self).partial_cmp(l.get(*other))
155109
}
156110
}
157111

158-
impl Ord for Interned<String> {
112+
impl<T: Internable + Ord> Ord for Interned<T> {
159113
fn cmp(&self, other: &Self) -> Ordering {
160-
let l = INTERNER.strs.lock().unwrap();
114+
let l = T::intern_cache().lock().unwrap();
161115
l.get(*self).cmp(l.get(*other))
162116
}
163117
}
@@ -210,6 +164,26 @@ pub struct Interner {
210164
paths: Mutex<TyIntern<PathBuf>>,
211165
}
212166

167+
trait Internable: Clone + Eq + Hash + 'static {
168+
fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
169+
170+
fn intern(self) -> Interned<Self> {
171+
Self::intern_cache().lock().unwrap().intern(self)
172+
}
173+
}
174+
175+
impl Internable for String {
176+
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
177+
&INTERNER.strs
178+
}
179+
}
180+
181+
impl Internable for PathBuf {
182+
fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
183+
&INTERNER.paths
184+
}
185+
}
186+
213187
impl Interner {
214188
pub fn intern_str(&self, s: &str) -> Interned<String> {
215189
self.strs.lock().unwrap().intern_borrow(s)

0 commit comments

Comments
 (0)