use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct StdImplCache {
impls: HashSet<(&'static str, &'static str)>,
}
impl StdImplCache {
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn has_impl(&self, type_name: &str, trait_name: &str) -> bool {
if self.impls.contains(&(type_name, trait_name)) {
return true;
}
let short_type = type_name.rsplit("::").next().unwrap_or(type_name);
let short_trait = trait_name.rsplit("::").next().unwrap_or(trait_name);
self.impls
.iter()
.any(|(t, tr)| *t == short_type && *tr == short_trait)
}
pub fn is_primitive(&self, type_name: &str) -> bool {
matches!(
type_name,
"i8" | "i16"
| "i32"
| "i64"
| "i128"
| "isize"
| "u8"
| "u16"
| "u32"
| "u64"
| "u128"
| "usize"
| "f32"
| "f64"
| "bool"
| "char"
| "()"
| "str"
)
}
pub fn is_std_container(&self, type_name: &str) -> bool {
let short = type_name.rsplit("::").next().unwrap_or(type_name);
matches!(
short,
"Vec"
| "String"
| "Option"
| "Result"
| "Box"
| "Rc"
| "Arc"
| "Cell"
| "RefCell"
| "HashMap"
| "HashSet"
| "BTreeMap"
| "BTreeSet"
| "VecDeque"
| "LinkedList"
| "BinaryHeap"
| "PathBuf"
| "OsString"
| "Cow"
)
}
pub fn traits_for(&self, type_name: &str) -> Vec<&'static str> {
let short = type_name.rsplit("::").next().unwrap_or(type_name);
self.impls
.iter()
.filter(|(t, _)| *t == short)
.map(|(_, tr)| *tr)
.collect()
}
}
impl Default for StdImplCache {
fn default() -> Self {
let mut impls = HashSet::new();
for prim in ["i8", "i16", "i32", "i64", "i128", "isize"] {
impls.insert((prim, "Clone"));
impls.insert((prim, "Copy"));
impls.insert((prim, "Debug"));
impls.insert((prim, "Default"));
impls.insert((prim, "PartialEq"));
impls.insert((prim, "Eq"));
impls.insert((prim, "PartialOrd"));
impls.insert((prim, "Ord"));
impls.insert((prim, "Hash"));
impls.insert((prim, "Send"));
impls.insert((prim, "Sync"));
}
for prim in ["u8", "u16", "u32", "u64", "u128", "usize"] {
impls.insert((prim, "Clone"));
impls.insert((prim, "Copy"));
impls.insert((prim, "Debug"));
impls.insert((prim, "Default"));
impls.insert((prim, "PartialEq"));
impls.insert((prim, "Eq"));
impls.insert((prim, "PartialOrd"));
impls.insert((prim, "Ord"));
impls.insert((prim, "Hash"));
impls.insert((prim, "Send"));
impls.insert((prim, "Sync"));
}
for prim in ["f32", "f64"] {
impls.insert((prim, "Clone"));
impls.insert((prim, "Copy"));
impls.insert((prim, "Debug"));
impls.insert((prim, "Default"));
impls.insert((prim, "PartialEq"));
impls.insert((prim, "PartialOrd"));
impls.insert((prim, "Send"));
impls.insert((prim, "Sync"));
}
impls.insert(("bool", "Clone"));
impls.insert(("bool", "Copy"));
impls.insert(("bool", "Debug"));
impls.insert(("bool", "Default"));
impls.insert(("bool", "PartialEq"));
impls.insert(("bool", "Eq"));
impls.insert(("bool", "PartialOrd"));
impls.insert(("bool", "Ord"));
impls.insert(("bool", "Hash"));
impls.insert(("bool", "Send"));
impls.insert(("bool", "Sync"));
impls.insert(("char", "Clone"));
impls.insert(("char", "Copy"));
impls.insert(("char", "Debug"));
impls.insert(("char", "PartialEq"));
impls.insert(("char", "Eq"));
impls.insert(("char", "PartialOrd"));
impls.insert(("char", "Ord"));
impls.insert(("char", "Hash"));
impls.insert(("char", "Send"));
impls.insert(("char", "Sync"));
impls.insert(("()", "Clone"));
impls.insert(("()", "Copy"));
impls.insert(("()", "Debug"));
impls.insert(("()", "Default"));
impls.insert(("()", "PartialEq"));
impls.insert(("()", "Eq"));
impls.insert(("()", "PartialOrd"));
impls.insert(("()", "Ord"));
impls.insert(("()", "Hash"));
impls.insert(("()", "Send"));
impls.insert(("()", "Sync"));
impls.insert(("String", "Clone"));
impls.insert(("String", "Debug"));
impls.insert(("String", "Default"));
impls.insert(("String", "PartialEq"));
impls.insert(("String", "Eq"));
impls.insert(("String", "PartialOrd"));
impls.insert(("String", "Ord"));
impls.insert(("String", "Hash"));
impls.insert(("String", "Send"));
impls.insert(("String", "Sync"));
impls.insert(("Vec", "Clone"));
impls.insert(("Vec", "Debug"));
impls.insert(("Vec", "Default"));
impls.insert(("Vec", "PartialEq"));
impls.insert(("Vec", "Eq"));
impls.insert(("Vec", "Hash"));
impls.insert(("Vec", "Send"));
impls.insert(("Vec", "Sync"));
impls.insert(("Option", "Clone"));
impls.insert(("Option", "Copy"));
impls.insert(("Option", "Debug"));
impls.insert(("Option", "Default"));
impls.insert(("Option", "PartialEq"));
impls.insert(("Option", "Eq"));
impls.insert(("Option", "PartialOrd"));
impls.insert(("Option", "Ord"));
impls.insert(("Option", "Hash"));
impls.insert(("Option", "Send"));
impls.insert(("Option", "Sync"));
impls.insert(("Result", "Clone"));
impls.insert(("Result", "Copy"));
impls.insert(("Result", "Debug"));
impls.insert(("Result", "PartialEq"));
impls.insert(("Result", "Eq"));
impls.insert(("Result", "PartialOrd"));
impls.insert(("Result", "Ord"));
impls.insert(("Result", "Hash"));
impls.insert(("Result", "Send"));
impls.insert(("Result", "Sync"));
impls.insert(("Box", "Clone"));
impls.insert(("Box", "Debug"));
impls.insert(("Box", "Default"));
impls.insert(("Box", "PartialEq"));
impls.insert(("Box", "Eq"));
impls.insert(("Box", "PartialOrd"));
impls.insert(("Box", "Ord"));
impls.insert(("Box", "Hash"));
impls.insert(("Box", "Send"));
impls.insert(("Box", "Sync"));
impls.insert(("Rc", "Clone"));
impls.insert(("Rc", "Debug"));
impls.insert(("Rc", "Default"));
impls.insert(("Rc", "PartialEq"));
impls.insert(("Rc", "Eq"));
impls.insert(("Rc", "PartialOrd"));
impls.insert(("Rc", "Ord"));
impls.insert(("Rc", "Hash"));
impls.insert(("Arc", "Clone"));
impls.insert(("Arc", "Debug"));
impls.insert(("Arc", "Default"));
impls.insert(("Arc", "PartialEq"));
impls.insert(("Arc", "Eq"));
impls.insert(("Arc", "PartialOrd"));
impls.insert(("Arc", "Ord"));
impls.insert(("Arc", "Hash"));
impls.insert(("Arc", "Send"));
impls.insert(("Arc", "Sync"));
impls.insert(("HashMap", "Clone"));
impls.insert(("HashMap", "Debug"));
impls.insert(("HashMap", "Default"));
impls.insert(("HashMap", "PartialEq"));
impls.insert(("HashMap", "Eq"));
impls.insert(("HashMap", "Send"));
impls.insert(("HashMap", "Sync"));
impls.insert(("HashSet", "Clone"));
impls.insert(("HashSet", "Debug"));
impls.insert(("HashSet", "Default"));
impls.insert(("HashSet", "PartialEq"));
impls.insert(("HashSet", "Eq"));
impls.insert(("HashSet", "Send"));
impls.insert(("HashSet", "Sync"));
impls.insert(("BTreeMap", "Clone"));
impls.insert(("BTreeMap", "Debug"));
impls.insert(("BTreeMap", "Default"));
impls.insert(("BTreeMap", "PartialEq"));
impls.insert(("BTreeMap", "Eq"));
impls.insert(("BTreeMap", "PartialOrd"));
impls.insert(("BTreeMap", "Ord"));
impls.insert(("BTreeMap", "Send"));
impls.insert(("BTreeMap", "Sync"));
impls.insert(("BTreeSet", "Clone"));
impls.insert(("BTreeSet", "Debug"));
impls.insert(("BTreeSet", "Default"));
impls.insert(("BTreeSet", "PartialEq"));
impls.insert(("BTreeSet", "Eq"));
impls.insert(("BTreeSet", "PartialOrd"));
impls.insert(("BTreeSet", "Ord"));
impls.insert(("BTreeSet", "Hash"));
impls.insert(("BTreeSet", "Send"));
impls.insert(("BTreeSet", "Sync"));
impls.insert(("PathBuf", "Clone"));
impls.insert(("PathBuf", "Debug"));
impls.insert(("PathBuf", "Default"));
impls.insert(("PathBuf", "PartialEq"));
impls.insert(("PathBuf", "Eq"));
impls.insert(("PathBuf", "PartialOrd"));
impls.insert(("PathBuf", "Ord"));
impls.insert(("PathBuf", "Hash"));
impls.insert(("PathBuf", "Send"));
impls.insert(("PathBuf", "Sync"));
impls.insert(("OsString", "Clone"));
impls.insert(("OsString", "Debug"));
impls.insert(("OsString", "Default"));
impls.insert(("OsString", "PartialEq"));
impls.insert(("OsString", "Eq"));
impls.insert(("OsString", "PartialOrd"));
impls.insert(("OsString", "Ord"));
impls.insert(("OsString", "Hash"));
impls.insert(("OsString", "Send"));
impls.insert(("OsString", "Sync"));
impls.insert(("Cell", "Clone"));
impls.insert(("Cell", "Copy"));
impls.insert(("Cell", "Debug"));
impls.insert(("Cell", "Default"));
impls.insert(("Cell", "PartialEq"));
impls.insert(("Cell", "Eq"));
impls.insert(("Cell", "PartialOrd"));
impls.insert(("Cell", "Ord"));
impls.insert(("Cell", "Send"));
impls.insert(("RefCell", "Clone"));
impls.insert(("RefCell", "Debug"));
impls.insert(("RefCell", "Default"));
impls.insert(("RefCell", "PartialEq"));
impls.insert(("RefCell", "Eq"));
impls.insert(("RefCell", "PartialOrd"));
impls.insert(("RefCell", "Ord"));
impls.insert(("RefCell", "Send"));
impls.insert(("Cow", "Clone"));
impls.insert(("Cow", "Debug"));
impls.insert(("Cow", "Default"));
impls.insert(("Cow", "PartialEq"));
impls.insert(("Cow", "Eq"));
impls.insert(("Cow", "PartialOrd"));
impls.insert(("Cow", "Ord"));
impls.insert(("Cow", "Hash"));
impls.insert(("Cow", "Send"));
impls.insert(("Cow", "Sync"));
impls.insert(("VecDeque", "Clone"));
impls.insert(("VecDeque", "Debug"));
impls.insert(("VecDeque", "Default"));
impls.insert(("VecDeque", "PartialEq"));
impls.insert(("VecDeque", "Eq"));
impls.insert(("VecDeque", "PartialOrd"));
impls.insert(("VecDeque", "Ord"));
impls.insert(("VecDeque", "Hash"));
impls.insert(("VecDeque", "Send"));
impls.insert(("VecDeque", "Sync"));
impls.insert(("PhantomData", "Clone"));
impls.insert(("PhantomData", "Copy"));
impls.insert(("PhantomData", "Debug"));
impls.insert(("PhantomData", "Default"));
impls.insert(("PhantomData", "PartialEq"));
impls.insert(("PhantomData", "Eq"));
impls.insert(("PhantomData", "PartialOrd"));
impls.insert(("PhantomData", "Ord"));
impls.insert(("PhantomData", "Hash"));
impls.insert(("PhantomData", "Send"));
impls.insert(("PhantomData", "Sync"));
Self { impls }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_primitive_impls() {
let cache = StdImplCache::new();
assert!(cache.has_impl("i32", "Clone"));
assert!(cache.has_impl("i32", "Copy"));
assert!(cache.has_impl("i32", "Debug"));
assert!(cache.has_impl("i32", "Default"));
assert!(cache.has_impl("i32", "Eq"));
assert!(cache.has_impl("i32", "Hash"));
assert!(cache.has_impl("f64", "Clone"));
assert!(cache.has_impl("f64", "PartialEq"));
assert!(!cache.has_impl("f64", "Eq"));
assert!(!cache.has_impl("f64", "Hash"));
}
#[test]
fn test_std_type_impls() {
let cache = StdImplCache::new();
assert!(cache.has_impl("String", "Clone"));
assert!(cache.has_impl("String", "Default"));
assert!(cache.has_impl("Vec", "Clone"));
assert!(cache.has_impl("HashMap", "Default"));
assert!(cache.has_impl("Rc", "Clone"));
assert!(!cache.has_impl("Rc", "Send"));
}
#[test]
fn test_normalized_lookup() {
let cache = StdImplCache::new();
assert!(cache.has_impl("std::string::String", "Clone"));
assert!(cache.has_impl("std::vec::Vec", "Default"));
}
#[test]
fn test_is_primitive() {
let cache = StdImplCache::new();
assert!(cache.is_primitive("i32"));
assert!(cache.is_primitive("f64"));
assert!(cache.is_primitive("bool"));
assert!(!cache.is_primitive("String"));
assert!(!cache.is_primitive("Vec"));
}
#[test]
fn test_traits_for() {
let cache = StdImplCache::new();
let bool_traits = cache.traits_for("bool");
assert!(bool_traits.contains(&"Clone"));
assert!(bool_traits.contains(&"Copy"));
assert!(bool_traits.contains(&"Eq"));
}
}