1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
use syn::{
punctuated::Punctuated, GenericArgument, Lifetime, Path, PathArguments, ReturnType, TraitBound,
Type, TypeParamBound,
};
#[allow(unused_variables)]
pub trait TypeMatcher<T> {
fn match_type<'a>(&self, t: &'a Type) -> Option<&'a T> {
None
}
fn match_path<'a>(&self, path: &'a Path) -> Option<&'a T> {
None
}
}
pub fn trait_bounds<T>(
bounds: &Punctuated<TypeParamBound, T>,
) -> impl Iterator<Item = &TraitBound> {
bounds.iter().filter_map(|b| match b {
TypeParamBound::Trait(t) => Some(t),
TypeParamBound::Lifetime(_) => None,
})
}
pub fn lifetime_bounds<T>(
bounds: &Punctuated<TypeParamBound, T>,
) -> impl Iterator<Item = &Lifetime> {
bounds.iter().filter_map(|b| match b {
TypeParamBound::Trait(_) => None,
TypeParamBound::Lifetime(l) => Some(l),
})
}
pub fn find_in_type<'a, T>(t: &'a Type, matcher: &dyn TypeMatcher<T>) -> Option<&'a T> {
if let Some(ret) = matcher.match_type(t) {
return Some(ret);
}
match t {
Type::Array(array) => find_in_type(&array.elem, matcher),
Type::BareFn(fun) => {
for input in &fun.inputs {
if let Some(ret) = find_in_type(&input.ty, matcher) {
return Some(ret);
}
}
if let ReturnType::Type(_, t) = &fun.output {
return find_in_type(t, matcher);
}
None
}
Type::Group(group) => find_in_type(&group.elem, matcher),
Type::ImplTrait(impltrait) => {
for bound in &impltrait.bounds {
if let TypeParamBound::Trait(bound) = bound {
if let Some(ret) = find_in_path(&bound.path, matcher) {
return Some(ret);
}
}
}
None
}
Type::Infer(_) => None,
Type::Macro(_) => None,
Type::Paren(paren) => find_in_type(&paren.elem, matcher),
Type::Path(path) => find_in_path(&path.path, matcher),
Type::Ptr(ptr) => find_in_type(&ptr.elem, matcher),
Type::Reference(reference) => find_in_type(&reference.elem, matcher),
Type::Slice(slice) => find_in_type(&slice.elem, matcher),
Type::TraitObject(traitobj) => {
for bound in &traitobj.bounds {
if let TypeParamBound::Trait(bound) = bound {
if let Some(ret) = find_in_path(&bound.path, matcher) {
return Some(ret);
}
}
}
None
}
Type::Tuple(tuple) => {
for elem in &tuple.elems {
if let Some(ret) = find_in_type(elem, matcher) {
return Some(ret);
}
}
None
}
_other => None,
}
}
pub fn find_in_path<'a, T>(path: &'a Path, matcher: &dyn TypeMatcher<T>) -> Option<&'a T> {
if let Some(ret) = matcher.match_path(path) {
return Some(ret);
}
for segment in &path.segments {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
for arg in &args.args {
if let GenericArgument::Type(t) = arg {
if let Some(ret) = find_in_type(t, matcher) {
return Some(ret);
}
}
}
}
}
None
}
|