cosmic_space/
kind2.rs

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, // Wrangles nearby Stars... manages Assigning Particles to Stars, Moving, Icing, etc.
148    Nexus, // Relays Waves from Star to Star
149    Maelstrom, // Where executables are run
150    Scribe, // requires durable filesystem (Artifact Bundles, Files...)
151    Jump, // for entry into the Mesh/Fabric for an external connection (client ingress... http for example)
152    Fold, // exit from the Mesh.. maintains connections etc to Databases, Keycloak, etc.... Like A Space Fold out of the Fabric..
153    Machine, // every Machine has one and only one Machine star... it handles messaging for the Machine
154}
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), //                  preceded_opt_pattern(|i|tag(":")(i), camel_case),
592        )(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            //            assert_eq!(selector.part.version,Pattern::Matches(VersionReq::from_str("1.0.0").unwrap()));
764
765            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}