Skip to main content

ryo_analysis/query/
std_impls.rs

1//! Standard library trait implementation cache.
2//!
3//! Provides statically known trait implementations for primitive types
4//! and common std types. This avoids needing to analyze std sources.
5
6use std::collections::HashSet;
7
8/// Cache of known trait implementations for standard library types.
9///
10/// This is a static cache that knows which primitives and std types
11/// implement common traits like Clone, Default, Debug, etc.
12#[derive(Debug, Clone)]
13pub struct StdImplCache {
14    /// Set of (type_name, trait_name) pairs that are implemented.
15    impls: HashSet<(&'static str, &'static str)>,
16}
17
18impl StdImplCache {
19    /// Create a new cache with default implementations.
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Check if a type implements a trait.
25    #[inline]
26    pub fn has_impl(&self, type_name: &str, trait_name: &str) -> bool {
27        // Direct lookup
28        if self.impls.contains(&(type_name, trait_name)) {
29            return true;
30        }
31
32        // Try normalized names (strip module path)
33        let short_type = type_name.rsplit("::").next().unwrap_or(type_name);
34        let short_trait = trait_name.rsplit("::").next().unwrap_or(trait_name);
35
36        self.impls
37            .iter()
38            .any(|(t, tr)| *t == short_type && *tr == short_trait)
39    }
40
41    /// Check if a type is a known primitive.
42    pub fn is_primitive(&self, type_name: &str) -> bool {
43        matches!(
44            type_name,
45            "i8" | "i16"
46                | "i32"
47                | "i64"
48                | "i128"
49                | "isize"
50                | "u8"
51                | "u16"
52                | "u32"
53                | "u64"
54                | "u128"
55                | "usize"
56                | "f32"
57                | "f64"
58                | "bool"
59                | "char"
60                | "()"
61                | "str"
62        )
63    }
64
65    /// Check if a type is a known std container.
66    pub fn is_std_container(&self, type_name: &str) -> bool {
67        let short = type_name.rsplit("::").next().unwrap_or(type_name);
68        matches!(
69            short,
70            "Vec"
71                | "String"
72                | "Option"
73                | "Result"
74                | "Box"
75                | "Rc"
76                | "Arc"
77                | "Cell"
78                | "RefCell"
79                | "HashMap"
80                | "HashSet"
81                | "BTreeMap"
82                | "BTreeSet"
83                | "VecDeque"
84                | "LinkedList"
85                | "BinaryHeap"
86                | "PathBuf"
87                | "OsString"
88                | "Cow"
89        )
90    }
91
92    /// Get all traits a type is known to implement.
93    pub fn traits_for(&self, type_name: &str) -> Vec<&'static str> {
94        let short = type_name.rsplit("::").next().unwrap_or(type_name);
95        self.impls
96            .iter()
97            .filter(|(t, _)| *t == short)
98            .map(|(_, tr)| *tr)
99            .collect()
100    }
101}
102
103impl Default for StdImplCache {
104    fn default() -> Self {
105        let mut impls = HashSet::new();
106
107        // === Primitive types ===
108        // Integer types (signed)
109        for prim in ["i8", "i16", "i32", "i64", "i128", "isize"] {
110            impls.insert((prim, "Clone"));
111            impls.insert((prim, "Copy"));
112            impls.insert((prim, "Debug"));
113            impls.insert((prim, "Default"));
114            impls.insert((prim, "PartialEq"));
115            impls.insert((prim, "Eq"));
116            impls.insert((prim, "PartialOrd"));
117            impls.insert((prim, "Ord"));
118            impls.insert((prim, "Hash"));
119            impls.insert((prim, "Send"));
120            impls.insert((prim, "Sync"));
121        }
122
123        // Integer types (unsigned)
124        for prim in ["u8", "u16", "u32", "u64", "u128", "usize"] {
125            impls.insert((prim, "Clone"));
126            impls.insert((prim, "Copy"));
127            impls.insert((prim, "Debug"));
128            impls.insert((prim, "Default"));
129            impls.insert((prim, "PartialEq"));
130            impls.insert((prim, "Eq"));
131            impls.insert((prim, "PartialOrd"));
132            impls.insert((prim, "Ord"));
133            impls.insert((prim, "Hash"));
134            impls.insert((prim, "Send"));
135            impls.insert((prim, "Sync"));
136        }
137
138        // Float types (no Eq, Ord, Hash)
139        for prim in ["f32", "f64"] {
140            impls.insert((prim, "Clone"));
141            impls.insert((prim, "Copy"));
142            impls.insert((prim, "Debug"));
143            impls.insert((prim, "Default"));
144            impls.insert((prim, "PartialEq"));
145            impls.insert((prim, "PartialOrd"));
146            impls.insert((prim, "Send"));
147            impls.insert((prim, "Sync"));
148        }
149
150        // bool
151        impls.insert(("bool", "Clone"));
152        impls.insert(("bool", "Copy"));
153        impls.insert(("bool", "Debug"));
154        impls.insert(("bool", "Default"));
155        impls.insert(("bool", "PartialEq"));
156        impls.insert(("bool", "Eq"));
157        impls.insert(("bool", "PartialOrd"));
158        impls.insert(("bool", "Ord"));
159        impls.insert(("bool", "Hash"));
160        impls.insert(("bool", "Send"));
161        impls.insert(("bool", "Sync"));
162
163        // char
164        impls.insert(("char", "Clone"));
165        impls.insert(("char", "Copy"));
166        impls.insert(("char", "Debug"));
167        impls.insert(("char", "PartialEq"));
168        impls.insert(("char", "Eq"));
169        impls.insert(("char", "PartialOrd"));
170        impls.insert(("char", "Ord"));
171        impls.insert(("char", "Hash"));
172        impls.insert(("char", "Send"));
173        impls.insert(("char", "Sync"));
174
175        // Unit type
176        impls.insert(("()", "Clone"));
177        impls.insert(("()", "Copy"));
178        impls.insert(("()", "Debug"));
179        impls.insert(("()", "Default"));
180        impls.insert(("()", "PartialEq"));
181        impls.insert(("()", "Eq"));
182        impls.insert(("()", "PartialOrd"));
183        impls.insert(("()", "Ord"));
184        impls.insert(("()", "Hash"));
185        impls.insert(("()", "Send"));
186        impls.insert(("()", "Sync"));
187
188        // === Common std types ===
189
190        // String
191        impls.insert(("String", "Clone"));
192        impls.insert(("String", "Debug"));
193        impls.insert(("String", "Default"));
194        impls.insert(("String", "PartialEq"));
195        impls.insert(("String", "Eq"));
196        impls.insert(("String", "PartialOrd"));
197        impls.insert(("String", "Ord"));
198        impls.insert(("String", "Hash"));
199        impls.insert(("String", "Send"));
200        impls.insert(("String", "Sync"));
201
202        // Vec<T> - conditional impls, assume T satisfies
203        impls.insert(("Vec", "Clone"));
204        impls.insert(("Vec", "Debug"));
205        impls.insert(("Vec", "Default"));
206        impls.insert(("Vec", "PartialEq"));
207        impls.insert(("Vec", "Eq"));
208        impls.insert(("Vec", "Hash"));
209        impls.insert(("Vec", "Send"));
210        impls.insert(("Vec", "Sync"));
211
212        // Option<T>
213        impls.insert(("Option", "Clone"));
214        impls.insert(("Option", "Copy"));
215        impls.insert(("Option", "Debug"));
216        impls.insert(("Option", "Default"));
217        impls.insert(("Option", "PartialEq"));
218        impls.insert(("Option", "Eq"));
219        impls.insert(("Option", "PartialOrd"));
220        impls.insert(("Option", "Ord"));
221        impls.insert(("Option", "Hash"));
222        impls.insert(("Option", "Send"));
223        impls.insert(("Option", "Sync"));
224
225        // Result<T, E>
226        impls.insert(("Result", "Clone"));
227        impls.insert(("Result", "Copy"));
228        impls.insert(("Result", "Debug"));
229        impls.insert(("Result", "PartialEq"));
230        impls.insert(("Result", "Eq"));
231        impls.insert(("Result", "PartialOrd"));
232        impls.insert(("Result", "Ord"));
233        impls.insert(("Result", "Hash"));
234        impls.insert(("Result", "Send"));
235        impls.insert(("Result", "Sync"));
236
237        // Box<T>
238        impls.insert(("Box", "Clone"));
239        impls.insert(("Box", "Debug"));
240        impls.insert(("Box", "Default"));
241        impls.insert(("Box", "PartialEq"));
242        impls.insert(("Box", "Eq"));
243        impls.insert(("Box", "PartialOrd"));
244        impls.insert(("Box", "Ord"));
245        impls.insert(("Box", "Hash"));
246        impls.insert(("Box", "Send"));
247        impls.insert(("Box", "Sync"));
248
249        // Rc<T> (not Send/Sync)
250        impls.insert(("Rc", "Clone"));
251        impls.insert(("Rc", "Debug"));
252        impls.insert(("Rc", "Default"));
253        impls.insert(("Rc", "PartialEq"));
254        impls.insert(("Rc", "Eq"));
255        impls.insert(("Rc", "PartialOrd"));
256        impls.insert(("Rc", "Ord"));
257        impls.insert(("Rc", "Hash"));
258
259        // Arc<T>
260        impls.insert(("Arc", "Clone"));
261        impls.insert(("Arc", "Debug"));
262        impls.insert(("Arc", "Default"));
263        impls.insert(("Arc", "PartialEq"));
264        impls.insert(("Arc", "Eq"));
265        impls.insert(("Arc", "PartialOrd"));
266        impls.insert(("Arc", "Ord"));
267        impls.insert(("Arc", "Hash"));
268        impls.insert(("Arc", "Send"));
269        impls.insert(("Arc", "Sync"));
270
271        // HashMap<K, V>
272        impls.insert(("HashMap", "Clone"));
273        impls.insert(("HashMap", "Debug"));
274        impls.insert(("HashMap", "Default"));
275        impls.insert(("HashMap", "PartialEq"));
276        impls.insert(("HashMap", "Eq"));
277        impls.insert(("HashMap", "Send"));
278        impls.insert(("HashMap", "Sync"));
279
280        // HashSet<T>
281        impls.insert(("HashSet", "Clone"));
282        impls.insert(("HashSet", "Debug"));
283        impls.insert(("HashSet", "Default"));
284        impls.insert(("HashSet", "PartialEq"));
285        impls.insert(("HashSet", "Eq"));
286        impls.insert(("HashSet", "Send"));
287        impls.insert(("HashSet", "Sync"));
288
289        // BTreeMap<K, V>
290        impls.insert(("BTreeMap", "Clone"));
291        impls.insert(("BTreeMap", "Debug"));
292        impls.insert(("BTreeMap", "Default"));
293        impls.insert(("BTreeMap", "PartialEq"));
294        impls.insert(("BTreeMap", "Eq"));
295        impls.insert(("BTreeMap", "PartialOrd"));
296        impls.insert(("BTreeMap", "Ord"));
297        impls.insert(("BTreeMap", "Send"));
298        impls.insert(("BTreeMap", "Sync"));
299
300        // BTreeSet<T>
301        impls.insert(("BTreeSet", "Clone"));
302        impls.insert(("BTreeSet", "Debug"));
303        impls.insert(("BTreeSet", "Default"));
304        impls.insert(("BTreeSet", "PartialEq"));
305        impls.insert(("BTreeSet", "Eq"));
306        impls.insert(("BTreeSet", "PartialOrd"));
307        impls.insert(("BTreeSet", "Ord"));
308        impls.insert(("BTreeSet", "Hash"));
309        impls.insert(("BTreeSet", "Send"));
310        impls.insert(("BTreeSet", "Sync"));
311
312        // PathBuf
313        impls.insert(("PathBuf", "Clone"));
314        impls.insert(("PathBuf", "Debug"));
315        impls.insert(("PathBuf", "Default"));
316        impls.insert(("PathBuf", "PartialEq"));
317        impls.insert(("PathBuf", "Eq"));
318        impls.insert(("PathBuf", "PartialOrd"));
319        impls.insert(("PathBuf", "Ord"));
320        impls.insert(("PathBuf", "Hash"));
321        impls.insert(("PathBuf", "Send"));
322        impls.insert(("PathBuf", "Sync"));
323
324        // OsString
325        impls.insert(("OsString", "Clone"));
326        impls.insert(("OsString", "Debug"));
327        impls.insert(("OsString", "Default"));
328        impls.insert(("OsString", "PartialEq"));
329        impls.insert(("OsString", "Eq"));
330        impls.insert(("OsString", "PartialOrd"));
331        impls.insert(("OsString", "Ord"));
332        impls.insert(("OsString", "Hash"));
333        impls.insert(("OsString", "Send"));
334        impls.insert(("OsString", "Sync"));
335
336        // Cell<T> (not Sync)
337        impls.insert(("Cell", "Clone"));
338        impls.insert(("Cell", "Copy"));
339        impls.insert(("Cell", "Debug"));
340        impls.insert(("Cell", "Default"));
341        impls.insert(("Cell", "PartialEq"));
342        impls.insert(("Cell", "Eq"));
343        impls.insert(("Cell", "PartialOrd"));
344        impls.insert(("Cell", "Ord"));
345        impls.insert(("Cell", "Send"));
346
347        // RefCell<T> (not Sync)
348        impls.insert(("RefCell", "Clone"));
349        impls.insert(("RefCell", "Debug"));
350        impls.insert(("RefCell", "Default"));
351        impls.insert(("RefCell", "PartialEq"));
352        impls.insert(("RefCell", "Eq"));
353        impls.insert(("RefCell", "PartialOrd"));
354        impls.insert(("RefCell", "Ord"));
355        impls.insert(("RefCell", "Send"));
356
357        // Cow<T>
358        impls.insert(("Cow", "Clone"));
359        impls.insert(("Cow", "Debug"));
360        impls.insert(("Cow", "Default"));
361        impls.insert(("Cow", "PartialEq"));
362        impls.insert(("Cow", "Eq"));
363        impls.insert(("Cow", "PartialOrd"));
364        impls.insert(("Cow", "Ord"));
365        impls.insert(("Cow", "Hash"));
366        impls.insert(("Cow", "Send"));
367        impls.insert(("Cow", "Sync"));
368
369        // VecDeque<T>
370        impls.insert(("VecDeque", "Clone"));
371        impls.insert(("VecDeque", "Debug"));
372        impls.insert(("VecDeque", "Default"));
373        impls.insert(("VecDeque", "PartialEq"));
374        impls.insert(("VecDeque", "Eq"));
375        impls.insert(("VecDeque", "PartialOrd"));
376        impls.insert(("VecDeque", "Ord"));
377        impls.insert(("VecDeque", "Hash"));
378        impls.insert(("VecDeque", "Send"));
379        impls.insert(("VecDeque", "Sync"));
380
381        // PhantomData<T>
382        impls.insert(("PhantomData", "Clone"));
383        impls.insert(("PhantomData", "Copy"));
384        impls.insert(("PhantomData", "Debug"));
385        impls.insert(("PhantomData", "Default"));
386        impls.insert(("PhantomData", "PartialEq"));
387        impls.insert(("PhantomData", "Eq"));
388        impls.insert(("PhantomData", "PartialOrd"));
389        impls.insert(("PhantomData", "Ord"));
390        impls.insert(("PhantomData", "Hash"));
391        impls.insert(("PhantomData", "Send"));
392        impls.insert(("PhantomData", "Sync"));
393
394        Self { impls }
395    }
396}
397
398#[cfg(test)]
399mod tests {
400    use super::*;
401
402    #[test]
403    fn test_primitive_impls() {
404        let cache = StdImplCache::new();
405
406        // i32 has all common traits
407        assert!(cache.has_impl("i32", "Clone"));
408        assert!(cache.has_impl("i32", "Copy"));
409        assert!(cache.has_impl("i32", "Debug"));
410        assert!(cache.has_impl("i32", "Default"));
411        assert!(cache.has_impl("i32", "Eq"));
412        assert!(cache.has_impl("i32", "Hash"));
413
414        // f64 has no Eq or Hash
415        assert!(cache.has_impl("f64", "Clone"));
416        assert!(cache.has_impl("f64", "PartialEq"));
417        assert!(!cache.has_impl("f64", "Eq"));
418        assert!(!cache.has_impl("f64", "Hash"));
419    }
420
421    #[test]
422    fn test_std_type_impls() {
423        let cache = StdImplCache::new();
424
425        assert!(cache.has_impl("String", "Clone"));
426        assert!(cache.has_impl("String", "Default"));
427        assert!(cache.has_impl("Vec", "Clone"));
428        assert!(cache.has_impl("HashMap", "Default"));
429
430        // Rc is not Send
431        assert!(cache.has_impl("Rc", "Clone"));
432        assert!(!cache.has_impl("Rc", "Send"));
433    }
434
435    #[test]
436    fn test_normalized_lookup() {
437        let cache = StdImplCache::new();
438
439        // Should work with full paths
440        assert!(cache.has_impl("std::string::String", "Clone"));
441        assert!(cache.has_impl("std::vec::Vec", "Default"));
442    }
443
444    #[test]
445    fn test_is_primitive() {
446        let cache = StdImplCache::new();
447
448        assert!(cache.is_primitive("i32"));
449        assert!(cache.is_primitive("f64"));
450        assert!(cache.is_primitive("bool"));
451        assert!(!cache.is_primitive("String"));
452        assert!(!cache.is_primitive("Vec"));
453    }
454
455    #[test]
456    fn test_traits_for() {
457        let cache = StdImplCache::new();
458
459        let bool_traits = cache.traits_for("bool");
460        assert!(bool_traits.contains(&"Clone"));
461        assert!(bool_traits.contains(&"Copy"));
462        assert!(bool_traits.contains(&"Eq"));
463    }
464}