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::ecosystem::Dependency for $type {
59 fn name(&self) -> &$crate::PackageName {
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<&$crate::VersionReq> {
68 self.$version.as_ref()
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 fn as_any(&self) -> &dyn ::std::any::Any {
80 self
81 }
82 }
83 };
84}
85
86#[macro_export]
164macro_rules! impl_version {
165 ($type:ty {
166 version: $version:ident,
167 status: $status:expr $(,)?
168 }) => {
169 impl $crate::registry::Version for $type {
170 fn version_string(&self) -> &$crate::ConcreteVersion {
171 &self.$version
172 }
173
174 fn removal_status(&self) -> $crate::registry::RemovalStatus {
175 ($status)(self)
176 }
177
178 fn as_any(&self) -> &dyn ::std::any::Any {
179 self
180 }
181 }
182 };
183 ($type:ty {
184 version: $version:ident,
185 status: $status:expr,
186 published_at: $published_at:ident $(,)?
187 }) => {
188 impl $crate::registry::Version for $type {
189 fn version_string(&self) -> &$crate::ConcreteVersion {
190 &self.$version
191 }
192
193 fn removal_status(&self) -> $crate::registry::RemovalStatus {
194 ($status)(self)
195 }
196
197 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
198 self.$published_at
199 }
200
201 fn as_any(&self) -> &dyn ::std::any::Any {
202 self
203 }
204 }
205 };
206 ($type:ty {
207 version: $version:ident,
208 status: $status:expr,
209 prerelease: $prerelease:expr $(,)?
210 }) => {
211 impl $crate::registry::Version for $type {
212 fn version_string(&self) -> &$crate::ConcreteVersion {
213 &self.$version
214 }
215
216 fn removal_status(&self) -> $crate::registry::RemovalStatus {
217 ($status)(self)
218 }
219
220 fn is_prerelease(&self) -> bool {
221 ($prerelease)(self)
222 }
223
224 fn as_any(&self) -> &dyn ::std::any::Any {
225 self
226 }
227 }
228 };
229 ($type:ty {
230 version: $version:ident,
231 status: $status:expr,
232 published_at: $published_at:ident,
233 prerelease: $prerelease:expr $(,)?
234 }) => {
235 impl $crate::registry::Version for $type {
236 fn version_string(&self) -> &$crate::ConcreteVersion {
237 &self.$version
238 }
239
240 fn removal_status(&self) -> $crate::registry::RemovalStatus {
241 ($status)(self)
242 }
243
244 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
245 self.$published_at
246 }
247
248 fn is_prerelease(&self) -> bool {
249 ($prerelease)(self)
250 }
251
252 fn as_any(&self) -> &dyn ::std::any::Any {
253 self
254 }
255 }
256 };
257 ($type:ty {
258 version: $version:ident,
259 status: $status:expr,
260 published_at: $published_at:ident,
261 prerelease: $prerelease:expr,
262 deprecation: $deprecation:expr $(,)?
263 }) => {
264 impl $crate::registry::Version for $type {
265 fn version_string(&self) -> &$crate::ConcreteVersion {
266 &self.$version
267 }
268
269 fn removal_status(&self) -> $crate::registry::RemovalStatus {
270 ($status)(self)
271 }
272
273 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
274 self.$published_at
275 }
276
277 fn is_prerelease(&self) -> bool {
278 ($prerelease)(self)
279 }
280
281 fn deprecation(&self) -> Option<&$crate::registry::Deprecation> {
282 let f: fn(&$type) -> Option<&$crate::registry::Deprecation> = $deprecation;
288 f(self)
289 }
290
291 fn as_any(&self) -> &dyn ::std::any::Any {
292 self
293 }
294 }
295 };
296}
297
298#[macro_export]
331macro_rules! impl_metadata {
332 ($type:ty {
333 name: $name:ident,
334 description: $description:ident,
335 repository: $repository:ident,
336 documentation: $documentation:ident,
337 latest_version: $latest_version:ident $(,)?
338 }) => {
339 impl $crate::registry::Metadata for $type {
340 fn name(&self) -> &$crate::PackageName {
341 &self.$name
342 }
343
344 fn description(&self) -> Option<&str> {
345 self.$description.as_deref()
346 }
347
348 fn repository(&self) -> Option<&str> {
349 self.$repository.as_deref()
350 }
351
352 fn documentation(&self) -> Option<&str> {
353 self.$documentation.as_deref()
354 }
355
356 fn latest_version(&self) -> &$crate::ConcreteVersion {
357 &self.$latest_version
358 }
359
360 fn as_any(&self) -> &dyn ::std::any::Any {
361 self
362 }
363 }
364 };
365}
366
367#[macro_export]
400macro_rules! impl_parse_result {
401 ($type:ty, $dep_type:ty {
402 dependencies: $dependencies:ident,
403 uri: $uri:ident $(,)?
404 }) => {
405 impl $crate::ecosystem::ParseResult for $type {
406 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
407 self.$dependencies
408 .iter()
409 .map(|d| d as &dyn $crate::ecosystem::Dependency)
410 .collect()
411 }
412
413 fn workspace_root(&self) -> Option<&::std::path::Path> {
414 None
415 }
416
417 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
418 &self.$uri
419 }
420
421 fn as_any(&self) -> &dyn ::std::any::Any {
422 self
423 }
424 }
425 };
426 ($type:ty, $dep_type:ty {
427 dependencies: $dependencies:ident,
428 uri: $uri:ident,
429 workspace_root: $workspace_root:ident $(,)?
430 }) => {
431 impl $crate::ecosystem::ParseResult for $type {
432 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
433 self.$dependencies
434 .iter()
435 .map(|d| d as &dyn $crate::ecosystem::Dependency)
436 .collect()
437 }
438
439 fn workspace_root(&self) -> Option<&::std::path::Path> {
440 self.$workspace_root.as_deref()
441 }
442
443 fn uri(&self) -> &::tower_lsp_server::ls_types::Uri {
444 &self.$uri
445 }
446
447 fn as_any(&self) -> &dyn ::std::any::Any {
448 self
449 }
450 }
451 };
452}
453
454#[cfg(test)]
455mod tests {
456 use crate::ConcreteVersion;
457 use tower_lsp_server::ls_types::{Position, Range, Uri};
458
459 #[derive(Debug, Clone)]
461 struct TestDependency {
462 name: crate::PackageName,
463 name_range: Range,
464 version_req: Option<crate::VersionReq>,
465 version_range: Option<Range>,
466 }
467
468 #[derive(Debug, Clone)]
469 struct TestVersion {
470 version: ConcreteVersion,
471 yanked: bool,
472 }
473
474 #[derive(Debug, Clone)]
475 struct TestVersionWithPublishedAt {
476 version: ConcreteVersion,
477 yanked: bool,
478 published_at: Option<crate::freshness::PublishTime>,
479 }
480
481 #[derive(Debug, Clone)]
482 struct TestVersionWithPrerelease {
483 version: ConcreteVersion,
484 yanked: bool,
485 }
486
487 #[derive(Debug, Clone)]
488 struct TestVersionWithPublishedAtAndPrerelease {
489 version: ConcreteVersion,
490 yanked: bool,
491 published_at: Option<crate::freshness::PublishTime>,
492 }
493
494 #[derive(Debug, Clone)]
495 struct TestPackage {
496 name: crate::PackageName,
497 description: Option<String>,
498 repository: Option<String>,
499 homepage: Option<String>,
500 latest_version: ConcreteVersion,
501 }
502
503 #[derive(Debug)]
504 struct TestParseResult {
505 dependencies: Vec<TestDependency>,
506 uri: Uri,
507 }
508
509 impl_dependency!(TestDependency {
511 name: name,
512 name_range: name_range,
513 version: version_req,
514 version_range: version_range,
515 });
516
517 impl_version!(TestVersion {
518 version: version,
519 status: |v: &TestVersion| crate::registry::RemovalStatus::from_yanked(v.yanked),
520 });
521
522 impl_version!(TestVersionWithPublishedAt {
523 version: version,
524 status: |v: &TestVersionWithPublishedAt| crate::registry::RemovalStatus::from_yanked(
525 v.yanked
526 ),
527 published_at: published_at,
528 });
529
530 impl_version!(TestVersionWithPrerelease {
531 version: version,
532 status: |v: &TestVersionWithPrerelease| crate::registry::RemovalStatus::from_yanked(
533 v.yanked
534 ),
535 prerelease: |v: &TestVersionWithPrerelease| v.version.as_str().contains(".pre"),
536 });
537
538 impl_version!(TestVersionWithPublishedAtAndPrerelease {
539 version: version,
540 status: |v: &TestVersionWithPublishedAtAndPrerelease| {
541 crate::registry::RemovalStatus::from_yanked(v.yanked)
542 },
543 published_at: published_at,
544 prerelease: |v: &TestVersionWithPublishedAtAndPrerelease| v
545 .version
546 .as_str()
547 .contains(".pre"),
548 });
549
550 impl_metadata!(TestPackage {
551 name: name,
552 description: description,
553 repository: repository,
554 documentation: homepage,
555 latest_version: latest_version,
556 });
557
558 impl_parse_result!(
559 TestParseResult,
560 TestDependency {
561 dependencies: dependencies,
562 uri: uri,
563 }
564 );
565
566 #[test]
567 fn test_impl_dependency_macro() {
568 use crate::ecosystem::Dependency;
569
570 let dep = TestDependency {
571 name: "test-pkg".into(),
572 name_range: Range::new(Position::new(0, 0), Position::new(0, 8)),
573 version_req: Some("1.0.0".into()),
574 version_range: Some(Range::new(Position::new(0, 10), Position::new(0, 15))),
575 };
576
577 assert_eq!(dep.name(), "test-pkg");
578 assert_eq!(
579 dep.version_requirement().map(crate::VersionReq::as_str),
580 Some("1.0.0")
581 );
582 assert!(dep.as_any().is::<TestDependency>());
583 }
584
585 #[test]
586 fn test_impl_version_macro() {
587 use crate::registry::Version;
588
589 let version = TestVersion {
590 version: "2.0.0".into(),
591 yanked: true,
592 };
593
594 assert_eq!(version.version_string().as_str(), "2.0.0");
595 assert!(version.removal_status().blocks_resolution());
596 assert!(version.as_any().is::<TestVersion>());
597 assert!(version.published_at().is_none());
598 }
599
600 #[test]
601 fn test_impl_version_macro_with_published_at() {
602 use crate::freshness::PublishTime;
603 use crate::registry::Version;
604
605 let version = TestVersionWithPublishedAt {
606 version: "3.0.0".into(),
607 yanked: false,
608 published_at: Some(PublishTime::from_unix_secs(1_000)),
609 };
610
611 assert_eq!(version.version_string().as_str(), "3.0.0");
612 assert!(!version.removal_status().blocks_resolution());
613 assert_eq!(
614 version.published_at(),
615 Some(PublishTime::from_unix_secs(1_000))
616 );
617 assert!(version.as_any().is::<TestVersionWithPublishedAt>());
618 }
619
620 #[test]
621 fn test_impl_version_macro_with_prerelease() {
622 use crate::registry::Version;
623
624 let stable = TestVersionWithPrerelease {
625 version: "1.0.0".into(),
626 yanked: false,
627 };
628 let prerelease = TestVersionWithPrerelease {
629 version: "1.0.0.pre1".into(),
630 yanked: false,
631 };
632
633 assert!(!stable.is_prerelease());
634 assert!(prerelease.is_prerelease());
635 assert!(stable.is_stable());
636 assert!(!prerelease.is_stable());
637 }
638
639 #[test]
640 fn test_impl_version_macro_with_published_at_and_prerelease() {
641 use crate::freshness::PublishTime;
642 use crate::registry::Version;
643
644 let version = TestVersionWithPublishedAtAndPrerelease {
645 version: "2.0.0.pre1".into(),
646 yanked: false,
647 published_at: Some(PublishTime::from_unix_secs(2_000)),
648 };
649
650 assert!(version.is_prerelease());
651 assert_eq!(
652 version.published_at(),
653 Some(PublishTime::from_unix_secs(2_000))
654 );
655 }
656
657 #[test]
658 fn test_impl_metadata_macro() {
659 use crate::registry::Metadata;
660
661 let pkg = TestPackage {
662 name: crate::PackageName::new("my-pkg"),
663 description: Some("A test package".into()),
664 repository: Some("user/repo".into()),
665 homepage: Some("https://example.com".into()),
666 latest_version: "3.0.0".into(),
667 };
668
669 assert_eq!(pkg.name(), "my-pkg");
670 assert_eq!(pkg.description(), Some("A test package"));
671 assert_eq!(pkg.documentation(), Some("https://example.com"));
672 assert!(pkg.as_any().is::<TestPackage>());
673 }
674
675 #[test]
676 fn test_impl_parse_result_macro() {
677 use crate::ecosystem::ParseResult;
678
679 let result = TestParseResult {
680 dependencies: vec![TestDependency {
681 name: "dep1".into(),
682 name_range: Range::default(),
683 version_req: None,
684 version_range: None,
685 }],
686 uri: crate::test_util::test_uri("/test"),
687 };
688
689 assert_eq!(result.dependencies().len(), 1);
690 assert!(result.workspace_root().is_none());
691 assert!(result.as_any().is::<TestParseResult>());
692 }
693}