1use crate::err::SpaceErr;
2use crate::loc::Version;
3use crate::parse::{CamelCase, Domain, SkewerCase};
4use crate::selector::VersionReq;
5use serde::{Deserialize, Serialize};
6use std::str::FromStr;
7
8#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
9pub struct SubTypeDef<Part, SubType> {
10 pub part: Part,
11 pub sub: SubType,
12 pub r#type: SubType,
13}
14
15impl<Part, SubType, IsMatchPart, IsMatchSubType> IsMatch<SubTypeDef<Part, SubType>>
16 for SubTypeDef<IsMatchPart, IsMatchSubType>
17where
18 IsMatchPart: IsMatch<Part>,
19 IsMatchSubType: IsMatch<SubType>,
20 Part: Eq + PartialEq,
21 SubType: Eq + PartialEq,
22{
23 fn is_match(&self, other: &SubTypeDef<Part, SubType>) -> bool {
24 self.part.is_match(&other.part)
25 && self.sub.is_match(&other.sub)
26 && self.r#type.is_match(&other.r#type)
27 }
28}
29
30impl<Part, SubType> SubTypeDef<Part, SubType> {
31 pub fn with_sub(self, sub: SubType) -> Self {
32 Self {
33 part: self.part,
34 r#type: self.r#type,
35 sub,
36 }
37 }
38
39 pub fn with_type(self, r#type: SubType) -> Self {
40 Self {
41 part: self.part,
42 sub: self.sub,
43 r#type,
44 }
45 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
49pub struct ParentChildDef<Parent, Child> {
50 pub parent: Parent,
51 pub child: Child,
52}
53
54impl<Parent, Child, IsMatchParent, IsMatchChild> IsMatch<ParentChildDef<Parent, Child>>
55 for ParentChildDef<IsMatchParent, IsMatchChild>
56where
57 IsMatchParent: IsMatch<Parent>,
58 IsMatchChild: IsMatch<Child>,
59 Parent: Eq + PartialEq,
60 Child: Eq + PartialEq,
61{
62 fn is_match(&self, other: &ParentChildDef<Parent, Child>) -> bool {
63 self.parent.is_match(&other.parent) && self.child.is_match(&other.child)
64 }
65}
66
67impl<Parent, Child> Default for ParentChildDef<Parent, Child>
68where
69 Parent: Default,
70 Child: Default,
71{
72 fn default() -> Self {
73 Self {
74 ..Default::default()
75 }
76 }
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, strum_macros::Display)]
80pub enum Variant {
81 Native(Native),
82 Artifact(Artifact),
83 Db(Db),
84 Star(StarVariant),
85}
86
87impl Variant {
88 pub fn from(kind: &Kind, variant: &CamelCase) -> Result<Self, SpaceErr> {
89 match kind {
90 what => Err(format!(
91 "kind '{}' does not have a variant '{}' ",
92 kind.to_string(),
93 variant.to_string()
94 )
95 .into()),
96 }
97 }
98}
99
100#[derive(
101 Debug,
102 Clone,
103 Serialize,
104 Deserialize,
105 Eq,
106 PartialEq,
107 Hash,
108 strum_macros::Display,
109 strum_macros::EnumString,
110)]
111pub enum Native {
112 Web,
113}
114
115#[derive(
116 Debug,
117 Clone,
118 Serialize,
119 Deserialize,
120 Eq,
121 PartialEq,
122 Hash,
123 strum_macros::Display,
124 strum_macros::EnumString,
125)]
126pub enum Artifact {
127 Repo,
128 Bundle,
129 Series,
130 Dir,
131 File,
132}
133
134#[derive(
135 Clone,
136 Debug,
137 Eq,
138 PartialEq,
139 Hash,
140 Serialize,
141 Deserialize,
142 strum_macros::Display,
143 strum_macros::EnumString,
144)]
145pub enum StarVariant {
146 Central,
147 Super, Nexus, Maelstrom, Scribe, Jump, Fold, Machine, }
155
156#[derive(
157 Debug,
158 Clone,
159 Serialize,
160 Deserialize,
161 Eq,
162 PartialEq,
163 Hash,
164 strum_macros::Display,
165 strum_macros::EnumString,
166)]
167pub enum Db {
168 Rel,
169}
170
171impl Variant {
172 pub fn to_sub_types(self) -> VariantSubTypes {
173 VariantSubTypes {
174 part: self,
175 sub: None,
176 r#type: None,
177 }
178 }
179
180 pub fn with_specific(self, specific: Option<SpecificSubTypes>) -> VariantFull {
181 VariantFull {
182 parent: self.to_sub_types(),
183 child: specific,
184 }
185 }
186}
187
188#[derive(
189 Debug,
190 Clone,
191 Serialize,
192 Deserialize,
193 Eq,
194 PartialEq,
195 Hash,
196 strum_macros::Display,
197 strum_macros::EnumString,
198)]
199pub enum Kind {
200 Root,
201 Space,
202 Base,
203 Account,
204 Mechtron,
205 Artifact,
206 Control,
207 Portal,
208 Star,
209 Driver,
210 Global,
211 Native,
212}
213
214impl Kind {
215 pub fn to_sub_types(self) -> KindSubTypes {
216 KindSubTypes {
217 part: self,
218 sub: None,
219 r#type: None,
220 }
221 }
222
223 pub fn with_variant(self, variant: Option<VariantFull>) -> KindFull {
224 KindFull {
225 parent: self.to_sub_types(),
226 child: variant,
227 }
228 }
229}
230
231impl Default for Kind {
232 fn default() -> Self {
233 Self::Root
234 }
235}
236
237#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)]
238pub struct SpecificDef<Domain, Skewer, Version> {
239 pub provider: Domain,
240 pub vendor: Domain,
241 pub product: Skewer,
242 pub variant: Skewer,
243 pub version: Version,
244}
245
246pub type Specific = SpecificDef<Domain, SkewerCase, Version>;
247
248impl Specific {
249 pub fn new(
250 provider: Domain,
251 vendor: Domain,
252 product: SkewerCase,
253 variant: SkewerCase,
254 version: Version,
255 ) -> Self {
256 Self {
257 provider,
258 vendor,
259 product,
260 variant,
261 version,
262 }
263 }
264
265 pub fn to_full(self) -> SpecificSubTypes {
266 SpecificSubTypes {
267 part: self,
268 sub: None,
269 r#type: None,
270 }
271 }
272
273 pub fn sub(self, sub: Option<CamelCase>) -> SpecificSubTypes {
274 SpecificSubTypes {
275 part: self,
276 sub,
277 r#type: None,
278 }
279 }
280
281 pub fn sub_type(self, sub: Option<CamelCase>, r#type: Option<CamelCase>) -> SpecificSubTypes {
282 SpecificSubTypes {
283 part: self,
284 sub,
285 r#type,
286 }
287 }
288}
289pub type VariantSubTypes = SubTypeDef<Variant, Option<CamelCase>>;
290
291pub type SpecificSubTypes = SubTypeDef<Specific, Option<CamelCase>>;
292pub type SpecificSubTypesSelector = SubTypeDef<Pattern<SpecificSelector>, OptPattern<CamelCase>>;
293
294pub type VariantDef<Variant, Specific> = ParentChildDef<Variant, Specific>;
295pub type VariantFull = VariantDef<VariantSubTypes, Option<SpecificSubTypes>>;
296pub type ProtoVariant = VariantDef<CamelCaseSubTypes, Option<SpecificSubTypes>>;
297pub type ProtoVariantSelector = VariantDef<CamelCaseSubTypes, SpecificSelector>;
298pub type KindDef<Kind, Variant> = ParentChildDef<Kind, Variant>;
299pub type CamelCaseSubTypes = SubTypeDef<CamelCase, Option<CamelCase>>;
300pub type CamelCaseSubTypesSelector = SubTypeDef<Pattern<CamelCase>, OptPattern<CamelCase>>;
301pub type KindSubTypes = SubTypeDef<Kind, Option<CamelCase>>;
302pub type KindFull = KindDef<KindSubTypes, Option<VariantFull>>;
303pub type ProtoKind = KindDef<CamelCaseSubTypes, Option<ProtoVariant>>;
304
305
306
307pub type ParentMatcherDef<Matcher, Child, SubTypeMatcher> =
308 ParentChildDef<SubTypeDef<Matcher, SubTypeMatcher>, Child>;
309
310pub trait IsMatch<X>
311where
312 X: Eq + PartialEq,
313{
314 fn is_match(&self, other: &X) -> bool;
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
318pub enum Pattern<X> {
319 None,
320 Any,
321 Matches(X),
322}
323
324impl<X> IsMatch<X> for Pattern<X>
325where
326 X: Eq + PartialEq,
327{
328 fn is_match(&self, other: &X) -> bool {
329 match self {
330 Pattern::None => false,
331 Pattern::Any => true,
332 Pattern::Matches(x) => x.eq(other),
333 }
334 }
335}
336
337impl<X> ToString for Pattern<X>
338where
339 X: ToString,
340{
341 fn to_string(&self) -> String {
342 match self {
343 Pattern::None => "!".to_string(),
344 Pattern::Any => "*".to_string(),
345 Pattern::Matches(x) => x.to_string(),
346 }
347 }
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
351pub enum OptPattern<X> {
352 None,
353 Any,
354 Matches(X),
355}
356
357impl<X> IsMatch<Option<X>> for OptPattern<X>
358where
359 X: Eq + PartialEq,
360{
361 fn is_match(&self, other: &Option<X>) -> bool {
362 match self {
363 Self::None => other.is_none(),
364 Self::Any => true,
365 Self::Matches(x) => match other {
366 None => false,
367 Some(o) => *x == *o,
368 },
369 }
370 }
371}
372
373impl<X> ToString for OptPattern<X>
374where
375 X: ToString,
376{
377 fn to_string(&self) -> String {
378 match self {
379 Self::None => "!".to_string(),
380 Self::Any => "*".to_string(),
381 Self::Matches(x) => x.to_string(),
382 }
383 }
384}
385
386impl IsMatch<Version> for VersionReq {
387 fn is_match(&self, other: &Version) -> bool {
388 self.version.matches(&other.version)
389 }
390}
391
392pub type DomainSelector = Pattern<Domain>;
393pub type SkewerSelector = Pattern<SkewerCase>;
394pub type VersionSelector = Pattern<VersionReq>;
395pub type SpecificSelector = SpecificDef<DomainSelector, SkewerSelector, VersionSelector>;
396pub type SpecificFullSelector = SubTypeDef<SpecificSelector, OptPattern<CamelCase>>;
397
398impl SpecificSelector {
399 pub fn to_full(self) -> SpecificFullSelector {
400 SpecificFullSelector {
401 part: self,
402 sub: OptPattern::None,
403 r#type: OptPattern::None,
404 }
405 }
406}
407
408impl IsMatch<Specific> for SpecificSelector {
409 fn is_match(&self, other: &Specific) -> bool {
410 self.provider.is_match(&other.provider)
411 && self.vendor.is_match(&other.vendor)
412 && self.product.is_match(&other.product)
413 && self.variant.is_match(&other.variant)
414 }
415}
416
417pub type VariantFullSelector =
418 ParentMatcherDef<Pattern<Variant>, OptPattern<SpecificSubTypes>, OptPattern<CamelCase>>;
419pub type KindFullSelector =
420 ParentMatcherDef<Pattern<Kind>, OptPattern<VariantFullSelector>, OptPattern<CamelCase>>;
421
422pub mod parse {
423
424 use crate::kind2::{CamelCaseSubTypes, CamelCaseSubTypesSelector, KindDef, OptPattern, ParentChildDef, Pattern, ProtoKind, ProtoVariant, Specific, SpecificDef, SpecificFullSelector, SpecificSelector, SpecificSubTypes, SpecificSubTypesSelector, SubTypeDef, VariantDef};
425 use crate::parse::{camel_case, domain, skewer_case, version, version_req, CamelCase, Domain};
426 use cosmic_nom::{Res, Span};
427 use nom::branch::alt;
428 use nom::bytes::complete::tag;
429 use nom::combinator::{fail, opt, success, value};
430 use nom::sequence::{delimited, pair, preceded, tuple};
431 use std::str::FromStr;
432
433 pub fn pattern<I, FnX, X>(mut f: FnX) -> impl FnMut(I) -> Res<I, Pattern<X>> + Copy
434 where
435 I: Span,
436 FnX: FnMut(I) -> Res<I, X> + Copy,
437 X: Clone,
438 {
439 move |input| {
440 alt((
441 value(Pattern::Any, tag("*")),
442 value(Pattern::None, tag("!")),
443 |i| f(i).map(|(next, x)| (next, Pattern::Matches(x))),
444 ))(input)
445 }
446 }
447
448 pub fn opt_pattern<I, FnX, X>(mut f: FnX) -> impl FnMut(I) -> Res<I, OptPattern<X>> + Copy
449 where
450 I: Span,
451 FnX: FnMut(I) -> Res<I, X> + Copy,
452 X: Clone,
453 {
454 move |input| {
455 alt((
456 value(OptPattern::Any, tag("*")),
457 value(OptPattern::None, tag("!")),
458 |i| f(i).map(|(next, x)| (next, OptPattern::Matches(x))),
459 ))(input)
460 }
461 }
462
463 pub fn preceded_opt_pattern<I, FnX, X, FnPrec>(
464 prec: FnPrec,
465 mut f: FnX,
466 ) -> impl FnMut(I) -> Res<I, OptPattern<X>> + Copy
467 where
468 I: Span,
469 FnX: FnMut(I) -> Res<I, X> + Copy,
470 X: Clone,
471 FnPrec: FnMut(I) -> Res<I, I> + Copy,
472 {
473 move |input| {
474 alt((preceded(prec, opt_pattern(f)), |i| {
475 Ok((i, OptPattern::None))
476 }))(input)
477 }
478 }
479
480 fn sub_types<I, FnPart, Part, FnCamel, Camel>(
481 fn_part: FnPart,
482 fn_camel: FnCamel,
483 ) -> impl FnMut(I) -> Res<I, SubTypeDef<Part, Camel>>
484 where
485 FnPart: FnMut(I) -> Res<I, Part> + Copy,
486 FnCamel: FnMut(I) -> Res<I, Camel> + Copy,
487 I: Span,
488 {
489 move |input: I| {
490 tuple((fn_part, fn_camel, fn_camel))(input)
491 .map(|(next, (part, sub, r#type))| (next, SubTypeDef { part, sub, r#type }))
492 }
493 }
494
495 fn parent_child_def<I, FnParent, Parent, FnChild, Child>(
496 fn_parent: FnParent,
497 fn_child: FnChild,
498 ) -> impl FnMut(I) -> Res<I, ParentChildDef<Parent, Child>>
499 where
500 FnParent: FnMut(I) -> Res<I, Parent> + Copy,
501 FnChild: FnMut(I) -> Res<I, Child> + Copy,
502 I: Span,
503 {
504 move |input: I| {
505 pair(fn_parent, fn_child)(input)
506 .map(|(next, (parent, child))| (next, ParentChildDef { parent, child }))
507 }
508 }
509
510 pub fn specific_def<I, FnDomain, FnSkewer, FnVersion, Domain, Skewer, Version>(
511 fn_domain: FnDomain,
512 fn_skewer: FnSkewer,
513 fn_version: FnVersion,
514 ) -> impl FnMut(I) -> Res<I, SpecificDef<Domain, Skewer, Version>> + Copy
515 where
516 I: Span,
517 FnDomain: FnMut(I) -> Res<I, Domain> + Copy,
518 FnSkewer: FnMut(I) -> Res<I, Skewer> + Copy,
519 FnVersion: FnMut(I) -> Res<I, Version> + Copy,
520 {
521 move |input: I| {
522 tuple((
523 fn_domain,
524 tag(":"),
525 fn_domain,
526 tag(":"),
527 fn_skewer,
528 tag(":"),
529 fn_skewer,
530 tag(":"),
531 fn_version,
532 ))(input)
533 .map(
534 |(next, (provider, _, vendor, _, product, _, variant, _, version))| {
535 (
536 next,
537 SpecificDef {
538 provider,
539 vendor,
540 product,
541 variant,
542 version,
543 },
544 )
545 },
546 )
547 }
548 }
549
550 pub fn specific<I>(input: I) -> Res<I, Specific>
551 where
552 I: Span,
553 {
554 specific_def(domain, skewer_case, version)(input)
555 }
556
557 pub fn specific_sub_types<I>(input: I) -> Res<I, SpecificSubTypes>
558 where
559 I: Span,
560 {
561 sub_types(specific, |i| opt(preceded(tag(":"), camel_case))(i))(input)
562 }
563
564 pub fn specific_selector<I>(input: I) -> Res<I, SpecificSelector>
565 where
566 I: Span,
567 {
568 specific_def(
569 pattern(domain),
570 pattern(skewer_case),
571 pattern(|i| delimited(tag("("), version_req, tag(")"))(i)),
572 )(input)
573 }
574
575 pub fn specific_sub_types_selector<I>(input: I) -> Res<I, SpecificSubTypesSelector>
576 where
577 I: Span,
578 {
579 sub_types(
580 pattern(specific_selector),
581 preceded_opt_pattern(|i| tag(":")(i), camel_case),
582 )(input)
583 }
584
585 pub fn specific_full_selector<I>(input: I) -> Res<I, SpecificFullSelector>
586 where
587 I: Span,
588 {
589 sub_types(
590 specific_selector,
591 preceded_opt_pattern(|i| tag(":")(i), camel_case), )(input)
593 }
594
595 pub fn variant_def<I, FnVariant, Variant, FnSpecific, Specific>(
596 variant: FnVariant,
597 specific: FnSpecific,
598 ) -> impl FnMut(I) -> Res<I, VariantDef<Variant, Specific>>
599 where
600 I: Span,
601 FnVariant: FnMut(I) -> Res<I, Variant> + Copy,
602 FnSpecific: FnMut(I) -> Res<I, Specific> + Copy,
603 {
604 move |input: I| parent_child_def(variant, specific)(input)
605 }
606
607 pub fn kind_def<I, FnKind, Kind, FnVariant, Variant>(
608 fn_kind: FnKind,
609 fn_variant: FnVariant,
610 ) -> impl FnMut(I) -> Res<I, KindDef<Kind, Variant>>
611 where
612 I: Span,
613 FnKind: FnMut(I) -> Res<I, Kind> + Copy,
614 FnVariant: FnMut(I) -> Res<I, Variant> + Copy,
615 {
616 move |input: I| parent_child_def(fn_kind, fn_variant)(input)
617 }
618
619
620 pub fn camel_case_sub_types<I>(input: I) -> Res<I, CamelCaseSubTypes>
621 where
622 I: Span,
623 {
624 sub_types(camel_case, |i| opt(preceded(tag(":"), camel_case))(i))(input)
625 }
626
627 pub fn camel_case_sub_types_selector<I>(input: I) -> Res<I, CamelCaseSubTypesSelector>
628 where
629 I: Span,
630 {
631 sub_types(
632 pattern(camel_case),
633 preceded_opt_pattern(|i| tag(":")(i), camel_case),
634 )(input)
635 }
636
637 pub fn child<I, F, R>(mut f: F) -> impl FnMut(I) -> Res<I, R>
638 where
639 I: Span,
640 F: FnMut(I) -> Res<I, R> + Copy,
641 {
642 move |input: I| delimited(tag("<"), f, tag(">"))(input)
643 }
644
645 pub fn proto_variant<I>(input: I) -> Res<I, ProtoVariant>
646 where
647 I: Span,
648 {
649 variant_def(camel_case_sub_types, |i| opt(child(specific_sub_types))(i))(input)
650 }
651
652 pub fn proto_kind<I>(input: I) -> Res<I, ProtoKind>
653 where
654 I: Span,
655 {
656 kind_def(camel_case_sub_types, |i| opt(child(proto_variant))(i) )(input)
657 }
658
659
660 #[cfg(test)]
661 pub mod test {
662 use crate::kind2::parse::{camel_case_sub_types, camel_case_sub_types_selector, opt_pattern, pattern, preceded_opt_pattern, proto_kind, proto_variant, specific, specific_full_selector, specific_selector, specific_sub_types};
663 use crate::kind2::{IsMatch, OptPattern, Pattern};
664
665 use crate::parse::error::result;
666 use crate::parse::{
667 camel_case, domain, expect, rec_version, skewer, version, version_req, CamelCase,
668 };
669 use crate::util::log;
670 use core::str::FromStr;
671 use cosmic_nom::new_span;
672 use nom::bytes::complete::tag;
673 use nom::combinator::{all_consuming, opt};
674 use nom::sequence::{delimited, pair, preceded};
675
676 #[test]
677 pub fn test_camel_case_subtypes() {
678 let r = result(expect(camel_case_sub_types)(new_span(
679 "SomeCamelCase:Sub:Type",
680 )))
681 .unwrap();
682 }
683
684 #[test]
685 pub fn test_camel_case_subtypes_selector() {
686 let r = result(camel_case_sub_types_selector(new_span(
687 "SomeCamelCase:*:Type",
688 )))
689 .unwrap();
690 match r.sub {
691 OptPattern::Any => {}
692 _ => assert!(false),
693 }
694 }
695
696 #[test]
697 pub fn test_my_sub() {
698 let sub = log(result(opt_pattern(camel_case)(new_span("MySub")))).unwrap();
699 assert_eq!(
700 sub,
701 OptPattern::Matches(CamelCase::from_str("MySub").unwrap())
702 );
703
704 let sub = log(result(preceded_opt_pattern(|i| tag(":")(i), camel_case)(
705 new_span(":MySub"),
706 )))
707 .unwrap();
708 assert_eq!(
709 sub,
710 OptPattern::Matches(CamelCase::from_str("MySub").unwrap())
711 );
712
713 let (blah, sub) = log(result(pair(
714 camel_case,
715 opt(preceded(tag(":"), camel_case)),
716 )(new_span("Blah:MySub"))))
717 .unwrap();
718 assert!(sub.is_some());
719
720 let (blah, sub) = log(result(pair(
721 camel_case,
722 preceded_opt_pattern(|i| tag(":")(i), camel_case),
723 )(new_span("Blah:MySub"))))
724 .unwrap();
725 assert!(sub.is_match(&Some(CamelCase::from_str("MySub").unwrap())))
726 }
727
728 #[test]
729 pub fn test_specific() {
730 let specific = result(specific(new_span(
731 "my-domain.io:vendor.io:product:variant:1.0.0",
732 )))
733 .unwrap();
734 }
735
736 #[test]
737 pub fn test_specific_selector() {
738 let selector = log(result(specific_selector(new_span(
739 "my-domain.io:*:product:variant:(1.0.0)",
740 ))))
741 .unwrap();
742 }
743
744 #[test]
745 pub fn test_specific_sub_types() {
746 let specific = result(specific_sub_types(new_span(
747 "my-domain.io:vendor.io:product:variant:1.0.0:Sub:Type",
748 )))
749 .unwrap();
750 assert_eq!(specific.sub, Some(CamelCase::from_str("Sub").unwrap()));
751 assert_eq!(specific.r#type, Some(CamelCase::from_str("Type").unwrap()));
752 }
753
754 #[test]
755 pub fn test_specific_full_selector() {
756 let selector = log(result(specific_full_selector(new_span(
757 "my-domain.io:*:product:variant:(1.0.0)",
758 ))))
759 .unwrap();
760
761 assert_eq!(selector.sub, OptPattern::None);
762 assert_eq!(selector.part.variant.to_string(), "variant".to_string());
763 let selector = log(result(specific_full_selector(new_span(
766 "my-domain.io:*:product:variant:(1.0.0):MySub",
767 ))))
768 .unwrap();
769
770 assert_eq!(
771 selector.sub,
772 OptPattern::Matches(CamelCase::from_str("MySub").unwrap())
773 );
774 }
775
776 #[test]
777 pub fn test_proto_variant() {
778 let variant = log(result(proto_variant(new_span("Variant")))).unwrap();
779 assert!(variant.child.is_none());
780
781 let variant = log(result(proto_variant(new_span(
782 "Variant<some.com:go.com:yesterday:tomorrow:1.0.0>",
783 ))))
784 .unwrap();
785 assert!(variant.child.is_some());
786
787 let variant = log(result(proto_variant(new_span("Variant:Sub")))).unwrap();
788 assert_eq!(variant.parent.part, CamelCase::from_str("Variant").unwrap());
789 assert!(variant.parent.sub.is_some());
790
791 let variant = log(result(proto_variant(new_span(
792 "Variant:Sub<some.com:go.com:yesterday:tomorrow:1.0.0>",
793 ))))
794 .unwrap();
795 assert!(variant.child.is_some());
796 assert!(variant.parent.sub.is_some());
797 }
798
799
800 #[test]
801 pub fn test_proto_kind() {
802 let kind = log(result(proto_kind(new_span("Root")))).unwrap();
803
804 let kind = log(result(proto_kind(new_span("Db:Sub")))).unwrap();
805 assert!(kind.parent.sub.is_some());
806
807 let kind = log(result(proto_kind(new_span("Db<Variant>")))).unwrap();
808 assert!(kind.child.is_some());
809
810 }
811
812
813
814 #[test]
815 pub fn test_camel_case_subtypes_err() {
816 assert!(log(result(expect(camel_case_sub_types)(new_span(
817 "someCamelCase:Sub:Type"
818 ))))
819 .is_err());
820 }
821 }
822}
823
824#[cfg(test)]
825pub mod test {
826 use crate::kind2::{
827 Artifact, DomainSelector, IsMatch, Kind, OptPattern, Pattern, SkewerSelector, Specific,
828 SpecificSelector, SpecificSubTypes, SubTypeDef, Variant, VariantFull, VariantFullSelector,
829 VersionSelector,
830 };
831 use crate::loc::Version;
832 use crate::parse::{CamelCase, Domain, SkewerCase};
833 use crate::selector::VersionReq;
834 use core::str::FromStr;
835
836 fn create_specific() -> Specific {
837 Specific::new(
838 Domain::from_str("my-domain.com").unwrap(),
839 Domain::from_str("my-domain.com").unwrap(),
840 SkewerCase::from_str("product").unwrap(),
841 SkewerCase::from_str("variant").unwrap(),
842 Version::from_str("1.0.0").unwrap(),
843 )
844 }
845
846 fn create_specific_sub_type() -> SpecificSubTypes {
847 create_specific().sub(Some(CamelCase::from_str("Blah").unwrap()))
848 }
849
850 fn create_variant_full() -> VariantFull {
851 Variant::Artifact(Artifact::Bundle).with_specific(Some(create_specific_sub_type()))
852 }
853
854 #[test]
855 pub fn specific() {
856 let specific1 = create_specific();
857 let specific2 = create_specific();
858 assert_eq!(specific1, specific2);
859
860 let spec1 = create_specific_sub_type();
861 let spec2 = create_specific_sub_type();
862 assert_eq!(spec1, spec2);
863 }
864
865 #[test]
866 pub fn variant() {
867 let var1 =
868 Variant::Artifact(Artifact::Bundle).with_specific(Some(create_specific_sub_type()));
869 let var2 =
870 Variant::Artifact(Artifact::Bundle).with_specific(Some(create_specific_sub_type()));
871 assert_eq!(var1, var2);
872 }
873
874 #[test]
875 pub fn kind() {
876 let kind1 = Kind::Root.with_variant(Some(create_variant_full()));
877 let kind2 = Kind::Root.with_variant(Some(create_variant_full()));
878 assert_eq!(kind1, kind2);
879 }
880
881 #[test]
882 pub fn specific_selector() {
883 let specific = create_specific();
884 let selector = SpecificSelector {
885 provider: DomainSelector::Any,
886 vendor: DomainSelector::Matches(Domain::from_str("my-domain.com").unwrap()),
887 product: SkewerSelector::Any,
888 variant: SkewerSelector::Matches(SkewerCase::from_str("variant").unwrap()),
889 version: VersionSelector::Matches(VersionReq::from_str("^1.0.0").unwrap()),
890 };
891
892 assert!(selector.is_match(&specific));
893
894 let mut specific = specific.to_full();
895 let mut selector = selector.to_full();
896
897 assert!(selector.is_match(&specific));
898
899 let specific = specific.with_sub(Some(CamelCase::from_str("Zophis").unwrap()));
900 assert!(!selector.is_match(&specific));
901 let selector = selector.with_sub(OptPattern::Any);
902 assert!(selector.is_match(&specific));
903
904 let selector = SpecificSelector {
905 provider: DomainSelector::Any,
906 vendor: DomainSelector::Matches(Domain::from_str("my-domain.com").unwrap()),
907 product: SkewerSelector::Any,
908 variant: SkewerSelector::Matches(SkewerCase::from_str("variant").unwrap()),
909 version: VersionSelector::Matches(VersionReq::from_str("^1.0.0").unwrap()),
910 };
911
912 let specific = create_specific();
913
914 assert!(selector.is_match(&specific));
915 }
916
917 #[test]
918 pub fn variant_selector() {
919 let variant = create_variant_full();
920 let mut selector = VariantFullSelector {
921 parent: SubTypeDef {
922 part: Pattern::Matches(Variant::Artifact(Artifact::Bundle)),
923 sub: OptPattern::None,
924 r#type: OptPattern::None,
925 },
926 child: OptPattern::None,
927 };
928
929 assert!(!selector.is_match(&variant));
930
931 let mut selector = VariantFullSelector {
932 parent: SubTypeDef {
933 part: Pattern::Matches(Variant::Artifact(Artifact::Bundle)),
934 sub: OptPattern::None,
935 r#type: OptPattern::None,
936 },
937 child: OptPattern::Any,
938 };
939
940 assert!(selector.is_match(&variant));
941 }
942}