aspect_core/pointcut/
pattern.rs1#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum Visibility {
6 Public,
8 Crate,
10 Super,
12 Private,
14}
15
16impl Visibility {
17 pub fn matches(&self, vis: &str) -> bool {
19 match (self, vis) {
20 (Visibility::Public, "pub") => true,
21 (Visibility::Crate, "pub(crate)") => true,
22 (Visibility::Super, "pub(super)") => true,
23 (Visibility::Private, "") => true,
24 _ => false,
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum NamePattern {
32 Wildcard,
34 Exact(String),
36 Prefix(String),
38 Suffix(String),
40 Contains(String),
42}
43
44impl NamePattern {
45 pub fn matches(&self, name: &str) -> bool {
47 match self {
48 NamePattern::Wildcard => true,
49 NamePattern::Exact(expected) => name == expected,
50 NamePattern::Prefix(prefix) => name.starts_with(prefix),
51 NamePattern::Suffix(suffix) => name.ends_with(suffix),
52 NamePattern::Contains(substring) => name.contains(substring),
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq)]
64pub struct ExecutionPattern {
65 pub visibility: Option<Visibility>,
67
68 pub name: NamePattern,
70
71 pub return_type: Option<String>,
73}
74
75impl ExecutionPattern {
76 pub fn any() -> Self {
78 Self {
79 visibility: None,
80 name: NamePattern::Wildcard,
81 return_type: None,
82 }
83 }
84
85 pub fn public() -> Self {
87 Self {
88 visibility: Some(Visibility::Public),
89 name: NamePattern::Wildcard,
90 return_type: None,
91 }
92 }
93
94 pub fn named(name: impl Into<String>) -> Self {
96 Self {
97 visibility: None,
98 name: NamePattern::Exact(name.into()),
99 return_type: None,
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct ModulePattern {
111 pub path: String,
113}
114
115impl ModulePattern {
116 pub fn new(path: impl Into<String>) -> Self {
118 Self {
119 path: path.into(),
120 }
121 }
122
123 pub fn matches_path(&self, module_path: &str) -> bool {
127 module_path == self.path || module_path.starts_with(&format!("{}::", self.path))
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_visibility_matches() {
137 assert!(Visibility::Public.matches("pub"));
138 assert!(Visibility::Crate.matches("pub(crate)"));
139 assert!(Visibility::Private.matches(""));
140 assert!(!Visibility::Public.matches("pub(crate)"));
141 }
142
143 #[test]
144 fn test_name_pattern_matches() {
145 let wildcard = NamePattern::Wildcard;
146 assert!(wildcard.matches("anything"));
147 assert!(wildcard.matches("save_user"));
148
149 let exact = NamePattern::Exact("save".to_string());
150 assert!(exact.matches("save"));
151 assert!(!exact.matches("save_user"));
152
153 let prefix = NamePattern::Prefix("save".to_string());
154 assert!(prefix.matches("save"));
155 assert!(prefix.matches("save_user"));
156 assert!(!prefix.matches("update_user"));
157
158 let suffix = NamePattern::Suffix("_user".to_string());
159 assert!(suffix.matches("save_user"));
160 assert!(suffix.matches("update_user"));
161 assert!(!suffix.matches("save"));
162 }
163
164 #[test]
165 fn test_module_pattern_matches() {
166 let pattern = ModulePattern::new("crate::api");
167
168 assert!(pattern.matches_path("crate::api"));
169 assert!(pattern.matches_path("crate::api::users"));
170 assert!(pattern.matches_path("crate::api::users::models"));
171 assert!(!pattern.matches_path("crate::internal"));
172 assert!(!pattern.matches_path("crate"));
173 }
174
175 #[test]
176 fn test_execution_pattern_builders() {
177 let any = ExecutionPattern::any();
178 assert_eq!(any.name, NamePattern::Wildcard);
179 assert!(any.visibility.is_none());
180
181 let public = ExecutionPattern::public();
182 assert_eq!(public.visibility, Some(Visibility::Public));
183
184 let named = ExecutionPattern::named("save_user");
185 assert_eq!(named.name, NamePattern::Exact("save_user".to_string()));
186 }
187}