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::VersionInfo 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
147 impl $crate::registry::Version for $type {
148 fn version_string(&self) -> &str {
149 &self.$version
150 }
151
152 fn is_yanked(&self) -> bool {
153 self.$yanked
154 }
155
156 fn as_any(&self) -> &dyn ::std::any::Any {
157 self
158 }
159 }
160 };
161}
162
163#[macro_export]
196macro_rules! impl_metadata {
197 ($type:ty {
198 name: $name:ident,
199 description: $description:ident,
200 repository: $repository:ident,
201 documentation: $documentation:ident,
202 latest_version: $latest_version:ident $(,)?
203 }) => {
204 impl $crate::registry::PackageMetadata for $type {
205 fn name(&self) -> &str {
206 &self.$name
207 }
208
209 fn description(&self) -> Option<&str> {
210 self.$description.as_deref()
211 }
212
213 fn repository(&self) -> Option<&str> {
214 self.$repository.as_deref()
215 }
216
217 fn documentation(&self) -> Option<&str> {
218 self.$documentation.as_deref()
219 }
220
221 fn latest_version(&self) -> &str {
222 &self.$latest_version
223 }
224 }
225
226 impl $crate::registry::Metadata for $type {
227 fn name(&self) -> &str {
228 &self.$name
229 }
230
231 fn description(&self) -> Option<&str> {
232 self.$description.as_deref()
233 }
234
235 fn repository(&self) -> Option<&str> {
236 self.$repository.as_deref()
237 }
238
239 fn documentation(&self) -> Option<&str> {
240 self.$documentation.as_deref()
241 }
242
243 fn latest_version(&self) -> &str {
244 &self.$latest_version
245 }
246
247 fn as_any(&self) -> &dyn ::std::any::Any {
248 self
249 }
250 }
251 };
252}
253
254#[macro_export]
287macro_rules! impl_parse_result {
288 ($type:ty, $dep_type:ty {
289 dependencies: $dependencies:ident,
290 uri: $uri:ident $(,)?
291 }) => {
292 impl $crate::ecosystem::ParseResult for $type {
293 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
294 self.$dependencies
295 .iter()
296 .map(|d| d as &dyn $crate::ecosystem::Dependency)
297 .collect()
298 }
299
300 fn workspace_root(&self) -> Option<&::std::path::Path> {
301 None
302 }
303
304 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
305 &self.$uri
306 }
307
308 fn as_any(&self) -> &dyn ::std::any::Any {
309 self
310 }
311 }
312 };
313 ($type:ty, $dep_type:ty {
314 dependencies: $dependencies:ident,
315 uri: $uri:ident,
316 workspace_root: $workspace_root:ident $(,)?
317 }) => {
318 impl $crate::ecosystem::ParseResult for $type {
319 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
320 self.$dependencies
321 .iter()
322 .map(|d| d as &dyn $crate::ecosystem::Dependency)
323 .collect()
324 }
325
326 fn workspace_root(&self) -> Option<&::std::path::Path> {
327 self.$workspace_root.as_deref()
328 }
329
330 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
331 &self.$uri
332 }
333
334 fn as_any(&self) -> &dyn ::std::any::Any {
335 self
336 }
337 }
338 };
339}
340
341#[macro_export]
356macro_rules! delegate_to_variants {
357 ($self:ident, $method:ident $(, $arg:expr)*) => {
358 match $self {
359 Self::Cargo(dep) => dep.$method($($arg),*),
360 Self::Npm(dep) => dep.$method($($arg),*),
361 Self::Pypi(dep) => dep.$method($($arg),*),
362 }
363 };
364}
365
366#[cfg(test)]
367mod tests {
368 use tower_lsp_server::ls_types::{Position, Range, Uri};
369
370 #[derive(Debug, Clone)]
372 struct TestDependency {
373 name: String,
374 name_range: Range,
375 version_req: Option<String>,
376 version_range: Option<Range>,
377 }
378
379 #[derive(Debug, Clone)]
380 struct TestVersion {
381 version: String,
382 yanked: bool,
383 }
384
385 #[derive(Debug, Clone)]
386 struct TestPackage {
387 name: String,
388 description: Option<String>,
389 repository: Option<String>,
390 homepage: Option<String>,
391 latest_version: String,
392 }
393
394 #[derive(Debug)]
395 struct TestParseResult {
396 dependencies: Vec<TestDependency>,
397 uri: Uri,
398 }
399
400 impl_dependency!(TestDependency {
402 name: name,
403 name_range: name_range,
404 version: version_req,
405 version_range: version_range,
406 });
407
408 impl_version!(TestVersion {
409 version: version,
410 yanked: yanked,
411 });
412
413 impl_metadata!(TestPackage {
414 name: name,
415 description: description,
416 repository: repository,
417 documentation: homepage,
418 latest_version: latest_version,
419 });
420
421 impl_parse_result!(
422 TestParseResult,
423 TestDependency {
424 dependencies: dependencies,
425 uri: uri,
426 }
427 );
428
429 #[test]
430 fn test_impl_dependency_macro() {
431 use crate::ecosystem::Dependency;
432
433 let dep = TestDependency {
434 name: "test-pkg".into(),
435 name_range: Range::new(Position::new(0, 0), Position::new(0, 8)),
436 version_req: Some("1.0.0".into()),
437 version_range: Some(Range::new(Position::new(0, 10), Position::new(0, 15))),
438 };
439
440 assert_eq!(dep.name(), "test-pkg");
441 assert_eq!(dep.version_requirement(), Some("1.0.0"));
442 assert!(dep.as_any().is::<TestDependency>());
443 }
444
445 #[test]
446 fn test_impl_version_macro() {
447 use crate::registry::Version;
448
449 let version = TestVersion {
450 version: "2.0.0".into(),
451 yanked: true,
452 };
453
454 assert_eq!(version.version_string(), "2.0.0");
455 assert!(version.is_yanked());
456 assert!(version.as_any().is::<TestVersion>());
457 }
458
459 #[test]
460 fn test_impl_metadata_macro() {
461 use crate::registry::Metadata;
462
463 let pkg = TestPackage {
464 name: "my-pkg".into(),
465 description: Some("A test package".into()),
466 repository: Some("user/repo".into()),
467 homepage: Some("https://example.com".into()),
468 latest_version: "3.0.0".into(),
469 };
470
471 assert_eq!(pkg.name(), "my-pkg");
472 assert_eq!(pkg.description(), Some("A test package"));
473 assert_eq!(pkg.documentation(), Some("https://example.com"));
474 assert!(pkg.as_any().is::<TestPackage>());
475 }
476
477 #[test]
478 fn test_impl_parse_result_macro() {
479 use crate::ecosystem::ParseResult;
480
481 let result = TestParseResult {
482 dependencies: vec![TestDependency {
483 name: "dep1".into(),
484 name_range: Range::default(),
485 version_req: None,
486 version_range: None,
487 }],
488 uri: Uri::from_file_path("/test").unwrap(),
489 };
490
491 assert_eq!(result.dependencies().len(), 1);
492 assert!(result.workspace_root().is_none());
493 assert!(result.as_any().is::<TestParseResult>());
494 }
495}