about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jnelson@cloudflare.com>2022-06-26 21:06:24 -0500
committerJoshua Nelson <jnelson@cloudflare.com>2022-07-02 19:29:39 -0500
commit0566ade0b13fa5e4e09ea6d72fe7cb92a1cb13e3 (patch)
tree9d2bee8e773d8fe0eac2ba6e07eb83eb7f1780c7
parentee8e0bc5824be2a05f086649815b2e10473663ea (diff)
downloadrust-0566ade0b13fa5e4e09ea6d72fe7cb92a1cb13e3.tar.gz
rust-0566ade0b13fa5e4e09ea6d72fe7cb92a1cb13e3.zip
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.
-rw-r--r--src/bootstrap/cache.rs112
1 files changed, 43 insertions, 69 deletions
diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs
index 97f0bfdc484..72de0a090af 100644
--- a/src/bootstrap/cache.rs
+++ b/src/bootstrap/cache.rs
@@ -4,13 +4,12 @@ use std::cell::RefCell;
 use std::cmp::{Ord, Ordering, PartialOrd};
 use std::collections::HashMap;
 use std::convert::AsRef;
-use std::ffi::OsStr;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::sync::Mutex;
 
 // FIXME: replace with std::lazy after it gets stabilized and reaches beta
@@ -20,15 +19,9 @@ use crate::builder::Step;
 
 pub struct Interned<T>(usize, PhantomData<*const T>);
 
-impl Default for Interned<String> {
+impl<T: Internable + Default> Default for Interned<T> {
     fn default() -> Self {
-        INTERNER.intern_string(String::default())
-    }
-}
-
-impl Default for Interned<PathBuf> {
-    fn default() -> Self {
-        INTERNER.intern_path(PathBuf::default())
+        T::default().intern()
     }
 }
 
@@ -77,87 +70,48 @@ impl fmt::Display for Interned<String> {
     }
 }
 
-impl fmt::Debug for Interned<String> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s: &str = &*self;
-        f.write_fmt(format_args!("{:?}", s))
-    }
-}
-impl fmt::Debug for Interned<PathBuf> {
+impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
+where
+    Self: Deref<Target = U>,
+{
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s: &Path = &*self;
+        let s: &U = &*self;
         f.write_fmt(format_args!("{:?}", s))
     }
 }
 
-impl Hash for Interned<String> {
+impl<T: Internable + Hash> Hash for Interned<T> {
     fn hash<H: Hasher>(&self, state: &mut H) {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).hash(state)
     }
 }
 
-impl Hash for Interned<PathBuf> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let l = INTERNER.paths.lock().unwrap();
-        l.get(*self).hash(state)
-    }
-}
-
-impl Deref for Interned<String> {
-    type Target = str;
-    fn deref(&self) -> &'static str {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
-    }
-}
-
-impl Deref for Interned<PathBuf> {
-    type Target = Path;
-    fn deref(&self) -> &'static Path {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
-    }
-}
-
-impl AsRef<Path> for Interned<PathBuf> {
-    fn as_ref(&self) -> &'static Path {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
-    }
-}
-
-impl AsRef<Path> for Interned<String> {
-    fn as_ref(&self) -> &'static Path {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
+impl<T: Internable + Deref> Deref for Interned<T> {
+    type Target = T::Target;
+    fn deref(&self) -> &'static Self::Target {
+        let l = T::intern_cache().lock().unwrap();
+        unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
     }
 }
 
-impl AsRef<OsStr> for Interned<PathBuf> {
-    fn as_ref(&self) -> &'static OsStr {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
+impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
+    fn as_ref(&self) -> &'static U {
+        let l = T::intern_cache().lock().unwrap();
+        unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
     }
 }
 
-impl AsRef<OsStr> for Interned<String> {
-    fn as_ref(&self) -> &'static OsStr {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
-    }
-}
-
-impl PartialOrd<Interned<String>> for Interned<String> {
+impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).partial_cmp(l.get(*other))
     }
 }
 
-impl Ord for Interned<String> {
+impl<T: Internable + Ord> Ord for Interned<T> {
     fn cmp(&self, other: &Self) -> Ordering {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).cmp(l.get(*other))
     }
 }
@@ -210,6 +164,26 @@ pub struct Interner {
     paths: Mutex<TyIntern<PathBuf>>,
 }
 
+trait Internable: Clone + Eq + Hash + 'static {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
+
+    fn intern(self) -> Interned<Self> {
+        Self::intern_cache().lock().unwrap().intern(self)
+    }
+}
+
+impl Internable for String {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
+        &INTERNER.strs
+    }
+}
+
+impl Internable for PathBuf {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
+        &INTERNER.paths
+    }
+}
+
 impl Interner {
     pub fn intern_str(&self, s: &str) -> Interned<String> {
         self.strs.lock().unwrap().intern_borrow(s)