1#[macro_export]
36macro_rules! impl_dependency {
37 ($type:ty {
38 name: $name:ident,
39 name_range: $name_range:ident,
40 version: $version:ident,
41 version_range: $version_range:ident $(,)?
42 }) => {
43 $crate::impl_dependency!($type {
44 name: $name,
45 name_range: $name_range,
46 version: $version,
47 version_range: $version_range,
48 source: $crate::parser::DependencySource::Registry,
49 });
50 };
51 ($type:ty {
52 name: $name:ident,
53 name_range: $name_range:ident,
54 version: $version:ident,
55 version_range: $version_range:ident,
56 source: $source:expr $(,)?
57 }) => {
58 impl $crate::parser::DependencyInfo for $type {
59 fn name(&self) -> &str {
60 &self.$name
61 }
62
63 fn name_range(&self) -> ::tower_lsp_server::ls_types::Range {
64 self.$name_range
65 }
66
67 fn version_requirement(&self) -> Option<&str> {
68 self.$version.as_deref()
69 }
70
71 fn version_range(&self) -> Option<::tower_lsp_server::ls_types::Range> {
72 self.$version_range
73 }
74
75 fn source(&self) -> $crate::parser::DependencySource {
76 $source
77 }
78 }
79
80 impl $crate::ecosystem::Dependency for $type {
81 fn name(&self) -> &str {
82 &self.$name
83 }
84
85 fn name_range(&self) -> ::tower_lsp_server::ls_types::Range {
86 self.$name_range
87 }
88
89 fn version_requirement(&self) -> Option<&str> {
90 self.$version.as_deref()
91 }
92
93 fn version_range(&self) -> Option<::tower_lsp_server::ls_types::Range> {
94 self.$version_range
95 }
96
97 fn source(&self) -> $crate::parser::DependencySource {
98 $source
99 }
100
101 fn as_any(&self) -> &dyn ::std::any::Any {
102 self
103 }
104 }
105 };
106}
107
108#[macro_export]
132macro_rules! impl_version {
133 ($type:ty {
134 version: $version:ident,
135 yanked: $yanked:ident $(,)?
136 }) => {
137 impl $crate::registry::Version for $type {
138 fn version_string(&self) -> &str {
139 &self.$version
140 }
141
142 fn is_yanked(&self) -> bool {
143 self.$yanked
144 }
145
146 fn as_any(&self) -> &dyn ::std::any::Any {
147 self
148 }
149 }
150 };
151}
152
153#[macro_export]
186macro_rules! impl_metadata {
187 ($type:ty {
188 name: $name:ident,
189 description: $description:ident,
190 repository: $repository:ident,
191 documentation: $documentation:ident,
192 latest_version: $latest_version:ident $(,)?
193 }) => {
194 impl $crate::registry::Metadata for $type {
195 fn name(&self) -> &str {
196 &self.$name
197 }
198
199 fn description(&self) -> Option<&str> {
200 self.$description.as_deref()
201 }
202
203 fn repository(&self) -> Option<&str> {
204 self.$repository.as_deref()
205 }
206
207 fn documentation(&self) -> Option<&str> {
208 self.$documentation.as_deref()
209 }
210
211 fn latest_version(&self) -> &str {
212 &self.$latest_version
213 }
214
215 fn as_any(&self) -> &dyn ::std::any::Any {
216 self
217 }
218 }
219 };
220}
221
222#[macro_export]
255macro_rules! impl_parse_result {
256 ($type:ty, $dep_type:ty {
257 dependencies: $dependencies:ident,
258 uri: $uri:ident $(,)?
259 }) => {
260 impl $crate::ecosystem::ParseResult for $type {
261 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
262 self.$dependencies
263 .iter()
264 .map(|d| d as &dyn $crate::ecosystem::Dependency)
265 .collect()
266 }
267
268 fn workspace_root(&self) -> Option<&::std::path::Path> {
269 None
270 }
271
272 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
273 &self.$uri
274 }
275
276 fn as_any(&self) -> &dyn ::std::any::Any {
277 self
278 }
279 }
280 };
281 ($type:ty, $dep_type:ty {
282 dependencies: $dependencies:ident,
283 uri: $uri:ident,
284 workspace_root: $workspace_root:ident $(,)?
285 }) => {
286 impl $crate::ecosystem::ParseResult for $type {
287 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
288 self.$dependencies
289 .iter()
290 .map(|d| d as &dyn $crate::ecosystem::Dependency)
291 .collect()
292 }
293
294 fn workspace_root(&self) -> Option<&::std::path::Path> {
295 self.$workspace_root.as_deref()
296 }
297
298 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
299 &self.$uri
300 }
301
302 fn as_any(&self) -> &dyn ::std::any::Any {
303 self
304 }
305 }
306 };
307}
308
309#[macro_export]
324macro_rules! delegate_to_variants {
325 ($self:ident, $method:ident $(, $arg:expr)*) => {
326 match $self {
327 Self::Cargo(dep) => dep.$method($($arg),*),
328 Self::Npm(dep) => dep.$method($($arg),*),
329 Self::Pypi(dep) => dep.$method($($arg),*),
330 }
331 };
332}
333
334#[cfg(test)]
335mod tests {
336 use tower_lsp_server::ls_types::{Position, Range, Uri};
337
338 #[derive(Debug, Clone)]
340 struct TestDependency {
341 name: String,
342 name_range: Range,
343 version_req: Option<String>,
344 version_range: Option<Range>,
345 }
346
347 #[derive(Debug, Clone)]
348 struct TestVersion {
349 version: String,
350 yanked: bool,
351 }
352
353 #[derive(Debug, Clone)]
354 struct TestPackage {
355 name: String,
356 description: Option<String>,
357 repository: Option<String>,
358 homepage: Option<String>,
359 latest_version: String,
360 }
361
362 #[derive(Debug)]
363 struct TestParseResult {
364 dependencies: Vec<TestDependency>,
365 uri: Uri,
366 }
367
368 impl_dependency!(TestDependency {
370 name: name,
371 name_range: name_range,
372 version: version_req,
373 version_range: version_range,
374 });
375
376 impl_version!(TestVersion {
377 version: version,
378 yanked: yanked,
379 });
380
381 impl_metadata!(TestPackage {
382 name: name,
383 description: description,
384 repository: repository,
385 documentation: homepage,
386 latest_version: latest_version,
387 });
388
389 impl_parse_result!(
390 TestParseResult,
391 TestDependency {
392 dependencies: dependencies,
393 uri: uri,
394 }
395 );
396
397 #[test]
398 fn test_impl_dependency_macro() {
399 use crate::ecosystem::Dependency;
400
401 let dep = TestDependency {
402 name: "test-pkg".into(),
403 name_range: Range::new(Position::new(0, 0), Position::new(0, 8)),
404 version_req: Some("1.0.0".into()),
405 version_range: Some(Range::new(Position::new(0, 10), Position::new(0, 15))),
406 };
407
408 assert_eq!(dep.name(), "test-pkg");
409 assert_eq!(dep.version_requirement(), Some("1.0.0"));
410 assert!(dep.as_any().is::<TestDependency>());
411 }
412
413 #[test]
414 fn test_impl_version_macro() {
415 use crate::registry::Version;
416
417 let version = TestVersion {
418 version: "2.0.0".into(),
419 yanked: true,
420 };
421
422 assert_eq!(version.version_string(), "2.0.0");
423 assert!(version.is_yanked());
424 assert!(version.as_any().is::<TestVersion>());
425 }
426
427 #[test]
428 fn test_impl_metadata_macro() {
429 use crate::registry::Metadata;
430
431 let pkg = TestPackage {
432 name: "my-pkg".into(),
433 description: Some("A test package".into()),
434 repository: Some("user/repo".into()),
435 homepage: Some("https://example.com".into()),
436 latest_version: "3.0.0".into(),
437 };
438
439 assert_eq!(pkg.name(), "my-pkg");
440 assert_eq!(pkg.description(), Some("A test package"));
441 assert_eq!(pkg.documentation(), Some("https://example.com"));
442 assert!(pkg.as_any().is::<TestPackage>());
443 }
444
445 #[test]
446 fn test_impl_parse_result_macro() {
447 use crate::ecosystem::ParseResult;
448
449 let result = TestParseResult {
450 dependencies: vec![TestDependency {
451 name: "dep1".into(),
452 name_range: Range::default(),
453 version_req: None,
454 version_range: None,
455 }],
456 uri: Uri::from_file_path("/test").unwrap(),
457 };
458
459 assert_eq!(result.dependencies().len(), 1);
460 assert!(result.workspace_root().is_none());
461 assert!(result.as_any().is::<TestParseResult>());
462 }
463}