starlane_resources/
lib.rs

1#[macro_use]
2extern crate strum_macros;
3
4use std::collections::{HashMap, HashSet};
5use std::convert::{TryFrom, TryInto};
6use std::str::FromStr;
7use std::sync::Arc;
8
9use nom::{AsChar, InputTakeAtPosition, IResult};
10use nom::branch::alt;
11use nom::bytes::complete::{tag, take};
12use nom::character::complete::{alpha0, alpha1, anychar, digit0, digit1, one_of};
13use nom::combinator::{not, opt};
14use nom::error::{context, ErrorKind, VerboseError};
15use nom::multi::{many1, many_m_n, separated_list0, separated_list1};
16use nom::sequence::{delimited, preceded, terminated, tuple};
17use semver::SemVerError;
18use serde::Deserialize;
19use serde::Serialize;
20
21use starlane_macros::resources;
22
23use crate::data::{BinSrc, DataSet};
24use crate::error::Error;
25use crate::message::{Fail, MessageFrom};
26
27pub mod data;
28pub mod error;
29pub mod parse;
30pub mod message;
31pub mod http;
32pub mod property;
33pub mod status;
34
35pub enum Galaxy{
36    Local,
37    Default,
38    Exact(DomainCase)
39}
40
41//pub type ResourcePath=crate::parse::ParsedResourcePath;
42
43#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
44pub struct ResourceAddress {
45    path: ResourcePathAndType,
46}
47
48impl ResourceAddress {
49    pub fn root() -> Self {
50        ResourcePathAndType::root().into()
51    }
52
53    pub fn new(path: ResourcePathAndType ) -> Self {
54        Self { path: path }
55    }
56
57    /*
58    pub fn append(&self, string: String, resource_type: ResourceType) -> Result<Self, Error> {
59        let path = format!(
60            "{}:{}",
61            self.path.to_string(),
62            string
63        );
64        let path = ResourcePath::from_str(path.as_str())?;
65        let path_and_kind = ResourcePathAndKind::new( path )
66        Ok(Self { path: path })
67    }*/
68
69    pub fn parent(&self) -> Option<ResourcePath> {
70        match self.path.parent() {
71            Option::None => Option::None,
72            Option::Some(parent) => Option::Some(parent.into()),
73        }
74    }
75
76    /*
77    pub fn ancestor_of_type(&self, resource_type: ResourceType) -> Result<ResourceAddress, Error> {
78        if self.resource_type() == resource_type {
79            return Ok(self.clone());
80        } else if let Option::Some(parent) = self.parent() {
81            parent.ancestor_of_type(resource_type)
82        } else {
83            Err(format!(
84                "does not have ancestor of type {}",
85                resource_type.to_string()
86            )
87            .into())
88        }
89    }
90     */
91
92    pub fn resource_type(&self) -> ResourceType {
93        self.path.resource_type.clone()
94    }
95
96    pub fn to_parts_string(&self) -> String {
97        self.path.to_string()
98    }
99
100    pub fn name(&self) -> String {
101        self.path.name()
102    }
103
104    pub fn last_to_string(&self) -> String {
105        self.name()
106    }
107}
108
109impl ToString for ResourceAddress {
110    fn to_string(&self) -> String {
111        format!(
112            "{}<{}>",
113            self.path.to_string(),
114            self.path.resource_type().to_string()
115        )
116    }
117}
118
119impl FromStr for ResourceAddress {
120    type Err = Error;
121
122    fn from_str(s: &str) -> Result<Self, Self::Err> {
123        Ok(ResourcePathAndType::from_str(s)?.into())
124    }
125}
126
127impl From<ResourcePathAndType> for ResourceAddress {
128    fn from(path: ResourcePathAndType ) -> Self {
129        Self { path: path }
130    }
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
134pub enum ResourcePropertyCategory {
135    State
136}
137
138impl ToString for ResourcePropertyCategory {
139    fn to_string(&self) -> String {
140        match self {
141            ResourcePropertyCategory::State => "state".to_string()
142        }
143    }
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
147pub struct ResourcePropertyAddress{
148  pub resource_address: ResourceAddress,
149  pub category: ResourcePropertyCategory,
150  pub aspect: Option<SkewerCase>,
151  pub meta_key: Option<String>
152}
153
154impl ToString for ResourcePropertyAddress {
155    fn to_string(&self) -> String {
156        let mut rtn = format!("{}::{}",self.resource_address.to_string(), self.category.to_string() );
157        if self.aspect.is_some() {
158           rtn.push_str( format!(".{}", self.aspect.as_ref().expect("aspect").to_string() ).as_str() );
159            if self.meta_key.is_some() {
160                rtn.push_str( format!("['{}']", self.meta_key.as_ref().expect("meta_key").clone() ).as_str() );
161            }
162        }
163
164        rtn
165    }
166}
167
168impl ResourceKey {
169    pub fn ancestor_of_type(&self, resource_type: ResourceType) -> Result<ResourceKey, Error> {
170        if self.resource_type() == resource_type {
171            return Ok(self.clone());
172        } else if let Option::Some(parent) = self.parent() {
173            parent.ancestor_of_type(resource_type)
174        } else {
175            Err(format!(
176                "does not have ancestor of type {}",
177                resource_type.to_string()
178            )
179            .into())
180        }
181    }
182}
183
184
185/*
186pub struct ResourceAddressKind {
187    path: ResourcePathAndKind,
188}
189
190impl ResourceAddressKind {
191    pub fn new(path: ParsedResourcePath, kind: ResourceKind) -> Self {
192        let path = ResourcePathAndKind::new(path,kind);
193        Self {
194            path: path,
195        }
196    }
197
198    pub fn kind(&self) -> ResourceKind {
199        self.kind.clone()
200    }
201}
202
203impl ToString for ResourceAddressKind {
204    fn to_string(&self) -> String {
205        format!("{}{}", self.path.to_string(), self.kind.to_string())
206    }
207}
208
209impl FromStr for ResourceAddressKind {
210    type Err = Error;
211
212    fn from_str(s: &str) -> Result<Self, Self::Err> {
213        let path = ResourcePathAndKind::from_str(s)?;
214        let (_leftover, (_, kind)) = parse_path(s)?;
215        Ok(Self {
216            path: path,
217            kind: kind.try_into()?,
218        })
219    }
220}
221j
222 */
223
224pub type Res<T, U> = IResult<T, U, VerboseError<T>>;
225
226static RESOURCE_ADDRESS_DELIM: &str = ":";
227
228fn alphanumerichyphen1<T>(i: T) -> Res<T, T>
229where
230    T: InputTakeAtPosition,
231    <T as InputTakeAtPosition>::Item: AsChar,
232{
233    i.split_at_position1_complete(
234        |item| {
235            let char_item = item.as_char();
236            !(char_item == '-') && !(char_item.is_alpha() || char_item.is_dec_digit())
237        },
238        ErrorKind::AlphaNumeric,
239    )
240}
241
242fn pathchar<T>(i: T) -> Res<T, T>
243where
244    T: InputTakeAtPosition,
245    <T as InputTakeAtPosition>::Item: AsChar,
246{
247    i.split_at_position1_complete(
248        |item| {
249            let char_item = item.as_char();
250            !(char_item == '/')
251                && !(char_item == '.')
252                && !(char_item == '_')
253                && !(char_item == '-')
254                && !(char_item.is_alpha() || char_item.is_dec_digit())
255        },
256        ErrorKind::AlphaNumeric,
257    )
258}
259
260fn address<T>(i: T) -> Res<T, T>
261where
262    T: InputTakeAtPosition,
263    <T as InputTakeAtPosition>::Item: AsChar,
264{
265    i.split_at_position1_complete(
266        |item| {
267            let char_item = item.as_char();
268            !(char_item == '.')
269                && !(char_item == '/')
270                && !(char_item == ':')
271                && !(char_item == '-')
272                && !(char_item.is_alpha() || char_item.is_dec_digit())
273        },
274        ErrorKind::AlphaNumeric,
275    )
276}
277
278fn loweralphanumerichyphen1<T>(i: T) -> Res<T, T>
279where
280    T: InputTakeAtPosition,
281    <T as InputTakeAtPosition>::Item: AsChar,
282{
283    i.split_at_position1_complete(
284        |item| {
285            let char_item = item.as_char();
286            !(char_item == '-')
287                && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
288        },
289        ErrorKind::AlphaNumeric,
290    )
291}
292
293fn path(input: &str) -> Res<&str, Path> {
294    context("path", preceded(tag("/"), pathchar))(input).map(|(input, path)| {
295        let path = format!("/{}", path);
296        let path = Path::new(path.as_str());
297        (input, path)
298    })
299}
300
301fn host(input: &str) -> Res<&str, String> {
302    context(
303        "host",
304        alt((
305            tuple((many1(terminated(alphanumerichyphen1, tag("."))), alpha1)),
306            tuple((many_m_n(1, 1, alphanumerichyphen1), take(0 as usize))),
307        )),
308    )(input)
309    .map(|(next_input, mut res)| {
310        if !res.1.is_empty() {
311            res.0.push(res.1);
312        }
313        (next_input, res.0.join("."))
314    })
315}
316
317impl From<DomainCase> for DomainOrSkewerCase {
318    fn from(domain: DomainCase) -> Self {
319        Self {
320            string: domain.to_string()
321        }
322    }
323}
324
325impl From<SkewerCase> for DomainOrSkewerCase {
326    fn from(skewer: SkewerCase) -> Self {
327        Self {
328            string: skewer.to_string()
329        }
330    }
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
334pub struct DomainOrSkewerCase {
335    string: String,
336}
337
338impl FromStr for DomainOrSkewerCase {
339    type Err = Error;
340
341    fn from_str(s: &str) -> Result<Self, Self::Err> {
342        let (remaining, domain_or_skewer) = domain_or_skewer(s)?;
343        if remaining.len() > 0 {
344            Err(format!("remainig text '{}' when parsing domain-or-skewer-case: '{}'", remaining, s).into())
345        } else {
346            Ok(domain_or_skewer)
347        }
348    }
349}
350
351impl ToString for DomainOrSkewerCase {
352    fn to_string(&self) -> String {
353        self.string.clone()
354    }
355}
356
357
358#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
359pub struct DomainCase {
360    string: String,
361}
362
363impl DomainCase {
364    pub fn new( string: &str ) -> Self {
365        DomainCase{
366            string: string.to_string()
367        }
368    }
369}
370
371impl FromStr for DomainCase {
372    type Err = Error;
373
374    fn from_str(s: &str) -> Result<Self, Self::Err> {
375        let (remaining, domain) = domain(s)?;
376        if remaining.len() > 0 {
377            Err(format!("remainig text '{}' when parsing domain: '{}'", remaining, s).into())
378        } else {
379            Ok(domain)
380        }
381    }
382}
383
384impl ToString for DomainCase {
385    fn to_string(&self) -> String {
386        self.string.clone()
387    }
388}
389
390fn domain_or_skewer(input: &str) -> Res<&str, DomainOrSkewerCase> {
391    context(
392        "domain_or_skewer",
393        alt( ( skewer_segment, domain_segment ) ),
394    )(input)
395        .map(|(next_input, mut res)| {
396            let domain_or_skewer = DomainOrSkewerCase{ string: res.to_string() };
397            (next_input,domain_or_skewer)
398        })
399}
400
401
402fn domain(input: &str) -> Res<&str, DomainCase> {
403    context(
404        "domain",
405        tuple((
406            many1(terminated(loweralphanumerichyphen1, tag("."))),
407            loweralphanumerichyphen1,
408        )),
409    )(input)
410    .map(|(next_input, mut res)| {
411        if !res.1.is_empty() {
412            res.0.push(res.1);
413        }
414        (next_input, DomainCase::new(res.0.join(".").as_str()))
415    })
416}
417
418fn zero(input: &str) -> Res<&str, &str> {
419    context("zero", tag("0"))(input)
420}
421
422/*
423fn integer( input: &str) -> Res<&str,String> {
424    context( "int",
425             alt( (tag("0"),tuple((one_of("123456789"), opt(digit1)) ))) )(input).map( |(input,output)|{})
426}
427
428 */
429
430fn version_major_minor_patch(input: &str) -> Res<&str, (usize, usize, usize)> {
431    context(
432        "version_major_minor_patch",
433        tuple((
434            terminated(digit1, tag(".")),
435            terminated(digit1, tag(".")),
436            terminated(digit1, not(digit1)),
437        )),
438    )(input)
439    .map(|(next_input, res)| {
440        (
441            next_input,
442            (
443                res.0.parse().unwrap(),
444                res.1.parse().unwrap(),
445                res.2.parse().unwrap(),
446            ),
447        )
448    })
449}
450
451fn version(input: &str) -> Res<&str, Version> {
452    context(
453        "version",
454        tuple((version_major_minor_patch, opt(preceded(tag("-"), skewer)))),
455    )(input)
456    .map(|(next_input, ((major, minor, patch), release))| {
457        (next_input, Version::new(major, minor, patch, release))
458    })
459}
460
461fn specific(input: &str) -> Res<&str, Specific> {
462    context(
463        "specific",
464        tuple((
465            terminated(domain, tag(":")),
466            terminated(loweralphanumerichyphen1, tag(":")),
467            terminated(loweralphanumerichyphen1, tag(":")),
468            version,
469        )),
470    )(input)
471    .map(|(next_input, (vendor, product, variant, version))| {
472        (
473            next_input,
474            Specific {
475                vendor: vendor,
476                product: product.to_string(),
477                variant: variant.to_string(),
478                version: version,
479            },
480        )
481    })
482}
483
484pub fn parse_kind(input: &str) -> Res<&str, ResourceKindParts> {
485    context(
486        "kind",
487        delimited(
488            tag("<"),
489            tuple((
490                alpha1,
491                opt(delimited(
492                    tag("<"),
493                    tuple((alpha1, opt(delimited(tag("<"), specific, tag(">"))))),
494                    tag(">"),
495                )),
496            )),
497            tag(">"),
498        ),
499    )(input)
500    .map(|(input, (rt, more))| {
501        let kind = match &more {
502            None => Option::None,
503            Some((kind, _)) => Option::Some((*kind).clone().to_string()),
504        };
505        let spec = match &more {
506            None => Option::None,
507            Some((_, Option::Some(spec))) => Option::Some(spec.clone()),
508            _ => Option::None,
509        };
510        (
511            input,
512            ResourceKindParts {
513                resource_type: rt.to_string(),
514                kind: kind,
515                specific: spec,
516            },
517        )
518    })
519}
520
521pub fn parse_key(input: &str) -> Res<&str, Vec<ResourcePathSegment>> {
522    context(
523        "key",
524        separated_list1(
525            nom::character::complete::char(':'),
526            alt((path_segment, version_segment, domain_segment, skewer_segment)),
527        ),
528    )(input)
529}
530
531pub fn parse_resource_path(input: &str) -> Res<&str, Vec<ResourcePathSegment>> {
532    context(
533        "address-path",
534        separated_list0(
535            nom::character::complete::char(':'),
536            alt((path_segment, version_segment, domain_segment, skewer_segment)),
537        ),
538    )(input)
539}
540
541pub fn parse_path_segment(input: &str) -> Res<&str, ResourcePathSegment> {
542    context(
543        "parse_path_segment",
544            alt((path_segment, version_segment, domain_segment, skewer_segment)),
545    )(input)
546}
547
548
549pub fn parse_path(input: &str) -> Res<&str, (Vec<ResourcePathSegment>, ResourceKindParts)> {
550    context("address", tuple((parse_resource_path, parse_kind)))(input)
551}
552
553/*
554pub fn parse_resource_address(input: &str) -> Res<&str, ResourceAddress > {
555    context("address", tuple((parse_resource_path, parse_kind)))(input)
556}
557
558
559 */
560
561pub fn parse_resource_property(input: &str) -> Res<&str, (Vec<ResourcePathSegment>, ResourceKindParts)> {
562    context("resource_property", tuple((parse_resource_path, parse_kind)))(input)
563}
564
565fn skewer(input: &str) -> Res<&str, SkewerCase> {
566    context("skewer-case", loweralphanumerichyphen1)(input)
567        .map(|(input, skewer)| (input, SkewerCase::new(skewer)))
568}
569
570fn skewer_segment(input: &str) -> Res<&str, ResourcePathSegment> {
571    context("skewer-case-part", skewer)(input)
572        .map(|(input, skewer)| (input, ResourcePathSegment::SkewerCase(skewer)))
573}
574
575fn version_segment(input: &str) -> Res<&str, ResourcePathSegment> {
576    context("version-part", version)(input)
577        .map(|(input, version)| (input, ResourcePathSegment::Version(version)))
578}
579
580fn domain_segment(input: &str) -> Res<&str, ResourcePathSegment> {
581    context("domain-part", domain)(input)
582        .map(|(input, domain)| (input, ResourcePathSegment::Domain(domain)))
583}
584
585fn path_segment(input: &str) -> Res<&str, ResourcePathSegment> {
586    context("path-part", path)(input).map(|(input, path)| (input, ResourcePathSegment::Path(path)))
587}
588
589#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
590pub struct Specific {
591    pub vendor: DomainCase,
592    pub product: String,
593    pub variant: String,
594    pub version: Version,
595}
596
597impl ToString for Specific {
598    fn to_string(&self) -> String {
599        format!(
600            "{}:{}:{}:{}",
601            self.vendor.to_string(),
602            self.product,
603            self.variant,
604            self.version.to_string()
605        )
606    }
607}
608
609impl FromStr for Specific {
610    type Err = Error;
611
612    fn from_str(s: &str) -> Result<Self, Self::Err> {
613        let (leftover, specific) = specific(s)?;
614        if leftover.len() != 0 {
615            Err(format!(
616                "could not process '{}' portion of specific '{}'",
617                leftover, s
618            )
619            .into())
620        } else {
621            Ok(specific)
622        }
623    }
624}
625
626#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
627pub struct ResourceKindParts {
628    pub resource_type: String,
629    pub kind: Option<String>,
630    pub specific: Option<Specific>,
631}
632
633impl ToString for ResourceKindParts {
634    fn to_string(&self) -> String {
635        if self.specific.is_some() && self.kind.is_some() {
636            format!(
637                "<{}<{}<{}>>>",
638                self.resource_type,
639                self.kind.as_ref().unwrap().to_string(),
640                self.specific.as_ref().unwrap().to_string()
641            )
642        } else if self.kind.is_some() {
643            format!(
644                "<{}<{}>>",
645                self.resource_type,
646                self.kind.as_ref().unwrap().to_string()
647            )
648        } else {
649            format!("<{}>", self.resource_type)
650        }
651    }
652}
653
654impl FromStr for ResourceKindParts {
655    type Err = Error;
656
657    fn from_str(s: &str) -> Result<Self, Self::Err> {
658        let (leftover, rtn) = parse_kind(s)?;
659        if leftover.len() > 0 {
660            return Err(format!(
661                "ResourceKindParts ERROR: could not parse extra: '{}' in string '{}'",
662                leftover, s
663            )
664            .into());
665        }
666        Ok(rtn)
667    }
668}
669
670
671
672/*
673#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
674pub struct ResourceAddressKind {
675    pub address: ResourceAddress,
676    pub kind: ResourceKind
677}
678
679impl FromStr for ResourceAddressKind {
680    type Err = Error;
681
682    fn from_str(s: &str) -> Result<Self, Self::Err> {
683        let (leftover,(address,kind)) = parse_address(s)?;
684        if leftover.len() > 0 {
685            return Err(format!("Parse Error for ResourceAddressKind: leftover '{}' when parsing '{}'",leftover,s).into());
686        }
687
688        let kind = ResourceKind::try_from(kind)?;
689        let address = format!("{}::<{}>",address,kind.resource_type().to_string());
690        let address = ResourceAddress::from_str(address.as_str())?;
691
692        Ok(ResourceAddressKind{
693            address,
694            kind
695        })
696    }
697
698}
699
700impl Into<ResourceAddress> for ResourceAddressKind {
701    fn into(self) -> ResourceAddress {
702        self.address
703    }
704}
705 */
706
707#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
708pub struct SkewerCase {
709    string: String,
710}
711
712impl ToString for SkewerCase {
713    fn to_string(&self) -> String {
714        self.string.clone()
715    }
716}
717
718impl SkewerCase {
719    fn new(string: &str) -> Self {
720        Self {
721            string: string.to_string(),
722        }
723    }
724}
725
726impl Into<ResourcePathSegment> for SkewerCase {
727    fn into(self) -> ResourcePathSegment {
728        ResourcePathSegment::SkewerCase(self)
729    }
730}
731
732impl FromStr for SkewerCase {
733    type Err = Error;
734
735    fn from_str(s: &str) -> Result<Self, Self::Err> {
736        let (remaining, skewer) = skewer(s)?;
737        if remaining.len() > 0 {
738            Err(format!(
739                "could not parse skewer because of remaining: '{}' in skewer: '{}'",
740                remaining, s
741            )
742            .into())
743        } else {
744            Ok(skewer)
745        }
746    }
747}
748
749#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
750pub enum ResourcePathSegmentKind {
751    Domain,
752    SkewerCase,
753    DomainOrSkewerCase,
754    Email,
755    Version,
756    Path,
757    Root,
758}
759
760impl ToString for ResourcePathSegmentKind {
761    fn to_string(&self) -> String {
762        match self {
763            ResourcePathSegmentKind::Domain => "Domain".to_string(),
764            ResourcePathSegmentKind::SkewerCase => "Skewer".to_string(),
765            ResourcePathSegmentKind::Version => "Version".to_string(),
766            ResourcePathSegmentKind::Path => "Path".to_string(),
767            ResourcePathSegmentKind::Email => "Email".to_string(),
768            ResourcePathSegmentKind::Root => "Root".to_string(),
769            ResourcePathSegmentKind::DomainOrSkewerCase => "DomainOrSkewerCase".to_string()
770        }
771    }
772}
773
774impl ResourcePathSegmentKind {
775    pub fn matches(&self, part: &ResourcePathSegment) -> bool {
776        match part {
777            ResourcePathSegment::SkewerCase(_) => *self == Self::SkewerCase,
778            ResourcePathSegment::Path(_) => *self == Self::Path,
779            ResourcePathSegment::Version(_) => *self == Self::Version,
780            ResourcePathSegment::Email(_) => *self == Self::Email,
781            ResourcePathSegment::Domain(_) => *self == Self::Domain,
782            ResourcePathSegment::DomainOrSkewerCase(_) => *self == Self::DomainOrSkewerCase
783        }
784    }
785
786    pub fn from_str(&self, s: &str) -> Result<ResourcePathSegment, Error> {
787        let (leftover, segment) = parse_path_segment(s)?;
788        if leftover.len() > 0 {
789            Err(format!(
790                "could not parse entire path string: leftover: '{}' from '{}'",
791                leftover, s
792            )
793            .into())
794        } else if self.matches(&segment){
795            Ok(segment)
796        } else {
797            Err(format!(
798                "path segment mismatch. expected: {}, got: {}",
799                self.to_string(), segment.to_kind().to_string() ).into()
800            )
801        }
802    }
803}
804
805#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
806pub enum ResourcePathSegment {
807    SkewerCase(SkewerCase),
808    Domain(DomainCase),
809    DomainOrSkewerCase(DomainOrSkewerCase),
810    Path(Path),
811    Version(Version),
812    Email(String),
813}
814
815impl ResourcePathSegment {
816    pub fn to_kind(self) -> ResourcePathSegmentKind {
817        match self {
818            ResourcePathSegment::SkewerCase(_) => ResourcePathSegmentKind::SkewerCase,
819            ResourcePathSegment::Domain(_) => ResourcePathSegmentKind::Domain,
820            ResourcePathSegment::Path(_) => ResourcePathSegmentKind::Path,
821            ResourcePathSegment::Version(_) => ResourcePathSegmentKind::Version,
822            ResourcePathSegment::Email(_) => ResourcePathSegmentKind::Email,
823            ResourcePathSegment::DomainOrSkewerCase(_) => ResourcePathSegmentKind::DomainOrSkewerCase
824        }
825    }
826}
827
828impl ToString for ResourcePathSegment {
829    fn to_string(&self) -> String {
830        match self {
831            ResourcePathSegment::SkewerCase(skewer) => skewer.to_string(),
832            ResourcePathSegment::Path(path) => path.to_string(),
833            ResourcePathSegment::Version(version) => version.to_string(),
834            ResourcePathSegment::Email(email) => email.to_string(),
835            ResourcePathSegment::Domain(domain) => domain.to_string(),
836            ResourcePathSegment::DomainOrSkewerCase(domain_or_skewer) => domain_or_skewer.to_string()
837        }
838    }
839}
840
841pub struct ParentAddressPatternRecognizer<T> {
842    patterns: HashMap<AddressPattern, T>,
843}
844
845impl<T> ParentAddressPatternRecognizer<T> {
846    pub fn try_from(&self, _pattern: &AddressPattern) -> Result<T, Error> {
847        unimplemented!()
848        //        self.patterns.get(pattern ).cloned().ok_or(Error{message:"Could not find a match for ParentAddressPatternRecognizer".to_string()})
849    }
850}
851
852#[derive(Clone, Eq, PartialEq, Hash)]
853pub struct AddressPattern {
854    pattern: Vec<ResourcePathSegmentKind>,
855}
856
857impl From<Vec<ResourcePathSegment>> for AddressPattern {
858    fn from(parts: Vec<ResourcePathSegment>) -> Self {
859        Self {
860            pattern: parts.iter().map(|p| p.clone().to_kind()).collect(),
861        }
862    }
863}
864
865impl From<Vec<ResourcePathSegmentKind>> for AddressPattern {
866    fn from(parts: Vec<ResourcePathSegmentKind>) -> Self {
867        Self { pattern: parts }
868    }
869}
870
871pub struct KeyBit {
872    pub key_type: String,
873    pub id: u64,
874}
875
876pub struct KeyBits {
877    pub key_type: String,
878    pub bits: Vec<KeyBit>,
879}
880
881impl KeyBits {
882    pub fn parse_key_bits(input: &str) -> Res<&str, Vec<KeyBit>> {
883        context(
884            "key-bits",
885            separated_list1(nom::character::complete::char(':'), Self::parse_key_bit),
886        )(input)
887    }
888
889    pub fn parse_key_bit(input: &str) -> Res<&str, KeyBit> {
890        context("key-bit", tuple((alpha1, digit1)))(input).map(|(input, (key_type, id))| {
891            (
892                input,
893                KeyBit {
894                    key_type: key_type.to_string(),
895                    id: id.parse().unwrap(), // should not have an error since we know it is a digit
896                },
897            )
898        })
899    }
900}
901
902#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
903pub struct Path {
904    string: String,
905}
906
907impl Path {
908    fn new(string: &str) -> Self {
909        Path {
910            string: string.to_string(),
911        }
912    }
913
914    pub fn make_absolute(string: &str) -> Result<Self, Error> {
915        if string.starts_with("/") {
916            Path::from_str(string)
917        } else {
918            Path::from_str(format!("/{}", string).as_str())
919        }
920    }
921
922    pub fn bin(&self) -> Result<Vec<u8>, Error> {
923        let bin = bincode::serialize(self)?;
924        Ok(bin)
925    }
926
927    pub fn is_absolute(&self) -> bool {
928        self.string.starts_with("/")
929    }
930
931    pub fn cat(&self, path: &Path) -> Result<Self, Error> {
932        if self.string.ends_with("/") {
933            Path::from_str(format!("{}{}", self.string.as_str(), path.string.as_str()).as_str())
934        } else {
935            Path::from_str(format!("{}/{}", self.string.as_str(), path.string.as_str()).as_str())
936        }
937    }
938
939    pub fn parent(&self) -> Option<Path> {
940        let mut copy = self.string.clone();
941        if copy.len() <= 1 {
942            return Option::None;
943        }
944        copy.remove(0);
945        let split = self.string.split("/");
946        if split.count() <= 1 {
947            Option::None
948        } else {
949            let mut segments = vec![];
950            let mut split = copy.split("/");
951            while let Option::Some(segment) = split.next() {
952                segments.push(segment);
953            }
954            if segments.len() <= 1 {
955                return Option::None;
956            } else {
957                segments.pop();
958                let mut string = String::new();
959                for segment in segments {
960                    string.push_str("/");
961                    string.push_str(segment);
962                }
963                Option::Some(Path::new(string.as_str()))
964            }
965        }
966    }
967
968    pub fn last_segment(&self) -> Option<String> {
969        let split = self.string.split("/");
970        match split.last() {
971            None => Option::None,
972            Some(last) => Option::Some(last.to_string()),
973        }
974    }
975
976    pub fn to_relative(&self) -> String {
977        let mut rtn = self.string.clone();
978        rtn.remove(0);
979        rtn
980    }
981}
982
983impl Into<ResourcePathSegment> for Path {
984    fn into(self) -> ResourcePathSegment {
985        ResourcePathSegment::Path(self)
986    }
987}
988
989impl TryInto<Arc<Vec<u8>>> for Path {
990    type Error = Error;
991
992    fn try_into(self) -> Result<Arc<Vec<u8>>, Self::Error> {
993        Ok(Arc::new(bincode::serialize(&self)?))
994    }
995}
996
997impl TryFrom<Arc<Vec<u8>>> for Path {
998    type Error = Error;
999
1000    fn try_from(value: Arc<Vec<u8>>) -> Result<Self, Self::Error> {
1001        Ok(bincode::deserialize::<Self>(&value)?)
1002    }
1003}
1004
1005impl TryFrom<&str> for Path {
1006    type Error = Error;
1007
1008    fn try_from(value: &str) -> Result<Self, Self::Error> {
1009        Ok(Path::from_str(value)?)
1010    }
1011}
1012
1013impl TryFrom<String> for Path {
1014    type Error = Error;
1015
1016    fn try_from(value: String) -> Result<Self, Self::Error> {
1017        Ok(Path::from_str(value.as_str())?)
1018    }
1019}
1020
1021impl ToString for Path {
1022    fn to_string(&self) -> String {
1023        self.string.clone()
1024    }
1025}
1026
1027impl FromStr for Path {
1028    type Err = Error;
1029
1030    fn from_str(s: &str) -> Result<Self, Self::Err> {
1031        let (leftover, path) = path(s)?;
1032        if !leftover.is_empty() {
1033            return Err(format!("could not parse '{}' from path {}", leftover, s).into());
1034        }
1035        Ok(path)
1036    }
1037}
1038
1039#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
1040pub struct Version {
1041    major: usize,
1042    minor: usize,
1043    patch: usize,
1044    release: Option<SkewerCase>,
1045}
1046
1047impl Version {
1048    fn new(major: usize, minor: usize, patch: usize, release: Option<SkewerCase>) -> Self {
1049        Self {
1050            major,
1051            minor,
1052            patch,
1053            release,
1054        }
1055    }
1056}
1057
1058impl Version {
1059    pub fn as_semver(&self) -> Result<semver::Version, Error> {
1060        Ok(semver::Version::parse(self.to_string().as_str())?)
1061    }
1062}
1063
1064impl Into<ResourcePathSegment> for Version {
1065    fn into(self) -> ResourcePathSegment {
1066        ResourcePathSegment::Version(self)
1067    }
1068}
1069
1070impl ToString for Version {
1071    fn to_string(&self) -> String {
1072        match &self.release {
1073            None => {
1074                format!("{}.{}.{}", self.major, self.minor, self.patch)
1075            }
1076            Some(release) => {
1077                format!(
1078                    "{}.{}.{}-{}",
1079                    self.major,
1080                    self.minor,
1081                    self.patch,
1082                    release.to_string()
1083                )
1084            }
1085        }
1086    }
1087}
1088
1089impl FromStr for Version {
1090    type Err = Error;
1091
1092    fn from_str(s: &str) -> Result<Self, Self::Err> {
1093        let (remaining, version) = version(s)?;
1094        if remaining.len() > 0 {
1095            Err(format!(
1096                "could not parse '{}' portion for version string '{}",
1097                remaining, s
1098            )
1099            .into())
1100        } else {
1101            Ok(version)
1102        }
1103    }
1104}
1105
1106#[cfg(test)]
1107mod tests {
1108    use std::convert::TryInto;
1109    use std::str::FromStr;
1110
1111    use crate::{
1112        domain, DomainCase, KeyBits, parse_resource_path, path, ResourceAddress,
1113        ResourcePathSegment, SkewerCase, Specific, version,
1114    };
1115    use crate::{
1116        AppKey, DatabaseKey, DatabaseKind, ResourceKey, ResourceKind, ResourceType,
1117        RootKey, SpaceKey, SubSpaceKey,
1118    };
1119    use crate::error::Error;
1120    use crate::ResourcePath;
1121
1122    #[test]
1123    fn test_kind() -> Result<(), Error> {
1124        let specific = Specific::from_str("mysql.org:mysql:innodb:1.0.1")?;
1125        let kind = DatabaseKind::Relational(specific);
1126        println!("kind: {}", kind.to_string());
1127
1128        let parsed_kind = ResourceKind::from_str(kind.to_string().as_str())?;
1129        let parsed_kind: DatabaseKind = parsed_kind.try_into()?;
1130        assert_eq!(kind, parsed_kind);
1131        Ok(())
1132    }
1133
1134    #[test]
1135    fn test_key_bit() -> Result<(), Error> {
1136        let (leftover, bit) = KeyBits::parse_key_bit("ss0")?;
1137
1138        assert_eq!(leftover.len(), 0);
1139
1140        assert_eq!(bit.key_type, "ss".to_string());
1141        assert_eq!(bit.id, 0);
1142
1143        Ok(())
1144    }
1145
1146    #[test]
1147    fn test_key_bits() -> Result<(), Error> {
1148        let (leftover, bits) = KeyBits::parse_key_bits("ss0:e53:sub73")?;
1149
1150        assert_eq!(leftover.len(), 0);
1151
1152        let bit = bits.get(0).unwrap();
1153        assert_eq!(bit.key_type, "ss".to_string());
1154        assert_eq!(bit.id, 0);
1155
1156        let bit = bits.get(1).unwrap();
1157        assert_eq!(bit.key_type, "e".to_string());
1158        assert_eq!(bit.id, 53);
1159
1160        let bit = bits.get(2).unwrap();
1161        assert_eq!(bit.key_type, "sub".to_string());
1162        assert_eq!(bit.id, 73);
1163
1164        Ok(())
1165    }
1166
1167    #[test]
1168    fn test_key() -> Result<(), Error> {
1169        let space_key = SpaceKey::new(RootKey::new(), 0);
1170        let space_key: ResourceKey = space_key.into();
1171        println!("space_key.to_string() {}", space_key.to_string());
1172        let sub_space_key = SubSpaceKey::new(space_key.try_into()?, 0);
1173        let sub_space_key: ResourceKey = sub_space_key.into();
1174        println!("sub_space_key.to_string() {}", sub_space_key.to_string());
1175        let app_key = AppKey::new(sub_space_key.try_into()?, 1);
1176        let app_key_cp = app_key.clone();
1177        let app_key: ResourceKey = app_key.into();
1178        println!("app_key.to_string() {}", app_key.to_string());
1179        let db_key = DatabaseKey::new(app_key.try_into()?, 77);
1180        println!("db_key.to_string() {}", db_key.to_string());
1181        let db_key: ResourceKey = db_key.into();
1182        println!("db_key.to_snake_case() {}", db_key.to_snake_case());
1183        println!("db_key.to_skewer_case() {}", db_key.to_skewer_case());
1184
1185        let db_key2 = ResourceKey::from_str(db_key.to_string().as_str())?;
1186
1187        assert_eq!(db_key, db_key2);
1188
1189        let app_key: AppKey = db_key.parent().unwrap().try_into()?;
1190        println!("parent {}", app_key.to_string());
1191
1192        assert_eq!(app_key_cp, app_key);
1193
1194        Ok(())
1195    }
1196
1197    #[test]
1198    fn test_version() -> Result<(), Error> {
1199        let (leftover, version) = version("1.3.4-beta")?;
1200        assert_eq!(leftover.len(), 0);
1201
1202        assert_eq!(version.major, 1);
1203        assert_eq!(version.minor, 3);
1204        assert_eq!(version.patch, 4);
1205        assert_eq!(version.release, Option::Some(SkewerCase::new("beta")));
1206
1207        Ok(())
1208    }
1209    #[test]
1210    fn test_path() -> Result<(), Error> {
1211        let (leftover, path) = path("/end/of-the/World.xyz")?;
1212
1213        assert_eq!(leftover.len(), 0);
1214
1215        assert_eq!("/end/of-the/World.xyz".to_string(), path.to_string());
1216
1217        Ok(())
1218    }
1219
1220    #[test]
1221    fn test_domain() -> Result<(), Error> {
1222        let (leftover, domain) = domain("hello-kitty.com")?;
1223
1224        assert_eq!(leftover.len(), 0);
1225
1226        assert_eq!("hello-kitty.com".to_string(), domain.to_string());
1227
1228        Ok(())
1229    }
1230
1231    #[test]
1232    fn address_path() -> Result<(), Error> {
1233        let (leftover, address) =
1234            parse_resource_path("starlane.io:some-skewer-case:1.3.4-beta:/the/End/of/the.World")?;
1235
1236        assert_eq!(
1237            address.get(0),
1238            Option::Some(&ResourcePathSegment::Domain(DomainCase::new("starlane.io")))
1239        );
1240        assert_eq!(
1241            address.get(1),
1242            Option::Some(&ResourcePathSegment::SkewerCase(SkewerCase::new(
1243                "some-skewer-case"
1244            )))
1245        );
1246        assert_eq!(leftover.len(), 0);
1247
1248        if let ResourcePathSegment::Version(version) = address.get(2).cloned().unwrap() {
1249            assert_eq!(version.major, 1);
1250            assert_eq!(version.minor, 3);
1251            assert_eq!(version.patch, 4);
1252            assert_eq!(version.release, Option::Some(SkewerCase::new("beta")));
1253        } else {
1254            assert!(false);
1255        }
1256
1257        if let ResourcePathSegment::Path(path) = address.get(3).cloned().unwrap() {
1258            assert_eq!("/the/End/of/the.World".to_string(), path.to_string());
1259        } else {
1260            assert!(false);
1261        }
1262
1263        Ok(())
1264    }
1265
1266
1267
1268    #[test]
1269    fn test_resource_address() -> Result<(), Error> {
1270        let address = ResourceAddress::from_str(
1271            "space:sub-space:some-app:database<Database<Relational<mysql.org:mysql:innodb:1.0.0>>>",
1272        )?;
1273        assert_eq!(
1274            "space:sub-space:some-app:database<Database>".to_string(),
1275            address.to_string()
1276        );
1277
1278        Ok(())
1279    }
1280}
1281
1282pub enum ResourceStatePersistenceManager {
1283    None,
1284    Store,
1285    Host,
1286}
1287
1288#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
1289pub enum ResourceIdentifier {
1290    Key(ResourceKey),
1291    Address(ResourcePath),
1292}
1293
1294impl ResourceIdentifier {
1295
1296    pub fn is_root(&self) -> bool {
1297        match self {
1298            ResourceIdentifier::Key(key) => *key == ResourceKey::Root,
1299            ResourceIdentifier::Address(address) => address.is_root()
1300        }
1301    }
1302
1303    pub fn parent(&self) -> Option<ResourceIdentifier> {
1304        match self {
1305            ResourceIdentifier::Key(key) => {
1306                match key.parent() {
1307                    Some(parent) => Option::Some(parent.into()),
1308                    None => None
1309                }
1310            },
1311            ResourceIdentifier::Address(address) => {
1312                match address.parent() {
1313                    Some(parent) => Option::Some(parent.into()),
1314                    None => None
1315                }
1316            }
1317        }
1318    }
1319
1320    pub fn is_key(&self) -> bool {
1321        match self {
1322            ResourceIdentifier::Key(_) => true,
1323            ResourceIdentifier::Address(_) => false,
1324        }
1325    }
1326
1327    pub fn is_address(&self) -> bool {
1328        match self {
1329            ResourceIdentifier::Key(_) => false,
1330            ResourceIdentifier::Address(_) => true,
1331        }
1332    }
1333
1334    pub fn key_or(self, error_message: &str) -> Result<ResourceKey, Error> {
1335        match self {
1336            ResourceIdentifier::Key(key) => Ok(key),
1337            ResourceIdentifier::Address(_) => Err(error_message.into()),
1338        }
1339    }
1340
1341    pub fn address_or(self, error_message: &str) -> Result<ResourcePath, Error> {
1342        match self {
1343            ResourceIdentifier::Key(_) => Err(error_message.into()),
1344            ResourceIdentifier::Address(address) => Ok(address),
1345        }
1346    }
1347
1348    /*
1349    pub async fn to_key(mut self, starlane_api: &StarlaneApi ) -> Result<ResourceKey,Error> {
1350        match self{
1351            ResourceIdentifier::Key(key) => {Ok(key)}
1352            ResourceIdentifier::Address(address) => {
1353                Ok(starlane_api.fetch_resource_key(address).await?)
1354            }
1355        }
1356    }
1357
1358    pub async fn to_address(mut self, starlane_api: &StarlaneApi ) -> Result<ResourceAddress,Error> {
1359        match self{
1360            ResourceIdentifier::Address(address) => {Ok(address)}
1361            ResourceIdentifier::Key(key) => {
1362                Ok(starlane_api.fetch_resource_address(key).await?)
1363            }
1364        }
1365    }
1366
1367     */
1368}
1369
1370impl ResourceIdentifier {
1371    /*
1372    pub fn parent(&self) -> Option<ResourceIdentifier> {
1373        match self {
1374            ResourceIdentifier::Key(key) => match key.parent() {
1375                None => Option::None,
1376                Some(parent) => Option::Some(parent.into()),
1377            },
1378            ResourceIdentifier::Address(address) => match address.parent() {
1379                None => Option::None,
1380                Some(parent) => Option::Some(parent.into()),
1381            },
1382        }
1383    }
1384     */
1385
1386}
1387
1388impl From<ResourcePath> for ResourceIdentifier {
1389    fn from(address: ResourcePath) -> Self {
1390        ResourceIdentifier::Address(address)
1391    }
1392}
1393
1394impl From<ResourceKey> for ResourceIdentifier {
1395    fn from(key: ResourceKey) -> Self {
1396        ResourceIdentifier::Key(key)
1397    }
1398}
1399
1400/*
1401impl TryInto<ResourceKey> for ResourceIdentifier {
1402    type Error = Error;
1403
1404    fn try_into(self) -> Result<ResourceKey, Self::Error> {
1405        match self {
1406            ResourceIdentifier::Key(key) => Ok(key),
1407            ResourceIdentifier::Address(address) => Err(format!("resource identifier is not a key.  Instead got address: {}",address.to_string()).into()),
1408        }
1409    }
1410}
1411
1412 */
1413
1414impl TryInto<ResourcePath> for ResourceIdentifier {
1415    type Error = Error;
1416
1417    fn try_into(self) -> Result<ResourcePath, Self::Error> {
1418        match self {
1419            ResourceIdentifier::Key(_) => Err("resource identifier is not an address".into()),
1420            ResourceIdentifier::Address(address) => Ok(address),
1421        }
1422    }
1423}
1424
1425impl ToString for ResourceIdentifier {
1426    fn to_string(&self) -> String {
1427        match self {
1428            ResourceIdentifier::Key(key) => key.to_string(),
1429            ResourceIdentifier::Address(address) => address.to_string(),
1430        }
1431    }
1432}
1433
1434resources! {
1435    #[resource(parents(Root))]
1436    #[resource(prefix="s")]
1437    #[resource(ResourcePathSegmentKind::SkewerCase)]
1438    #[resource(ResourceStatePersistenceManager::Store)]
1439    #[resource(state(meta::Meta))]
1440    pub struct Space();
1441
1442    #[resource(parents(Space))]
1443    #[resource(prefix="app")]
1444    #[resource(ResourcePathSegmentKind::SkewerCase)]
1445    #[resource(ResourceStatePersistenceManager::None)]
1446    pub struct App();
1447
1448    #[resource(parents(App))]
1449    #[resource(prefix="mt")]
1450    #[resource(ResourcePathSegmentKind::SkewerCase)]
1451    #[resource(ResourceStatePersistenceManager::None)]
1452    pub struct Mechtron();
1453
1454    #[resource(parents(Space,App))]
1455    #[resource(prefix="fs")]
1456    #[resource(ResourcePathSegmentKind::SkewerCase)]
1457    #[resource(ResourceStatePersistenceManager::Host)]
1458    pub struct FileSystem();
1459
1460    #[resource(parents(FileSystem))]
1461    #[resource(prefix="f")]
1462    #[resource(ResourcePathSegmentKind::Path)]
1463    #[resource(ResourceStatePersistenceManager::Host)]
1464    #[resource(state(meta::Meta))]
1465    #[resource(state(content::Binary))]
1466    pub struct File();
1467
1468    #[resource(parents(Space))]
1469    #[resource(prefix="db")]
1470    #[resource(ResourcePathSegmentKind::SkewerCase)]
1471    #[resource(ResourceStatePersistenceManager::Host)]
1472    pub struct Database();
1473
1474    #[resource(parents(Space,App))]
1475    #[resource(prefix="auth")]
1476    #[resource(ResourcePathSegmentKind::SkewerCase)]
1477    #[resource(ResourceStatePersistenceManager::Host)]
1478    pub struct Authenticator();
1479
1480    #[resource(parents(Authenticator))]
1481    #[resource(prefix="creds")]
1482    #[resource(ResourcePathSegmentKind::SkewerCase)]
1483    #[resource(ResourceStatePersistenceManager::Host)]
1484    pub struct Credentials();
1485
1486    #[resource(parents(Space))]
1487    #[resource(prefix="p")]
1488    #[resource(ResourcePathSegmentKind::SkewerCase)]
1489    #[resource(ResourceStatePersistenceManager::None)]
1490    pub struct Proxy();
1491
1492    #[resource(parents(Space))]
1493    #[resource(prefix="abv")]
1494    #[resource(ResourcePathSegmentKind::SkewerCase)]
1495    #[resource(ResourceStatePersistenceManager::None)]
1496    #[resource(state(content::Binary))]
1497    pub struct ArtifactBundleSeries();
1498
1499    #[resource(parents(ArtifactBundleSeries))]
1500    #[resource(prefix="ab")]
1501    #[resource(ResourcePathSegmentKind::Version)]
1502    #[resource(ResourceStatePersistenceManager::Host)]
1503    #[resource(state(content::Binary))]
1504    pub struct ArtifactBundle();
1505
1506    #[resource(parents(ArtifactBundle))]
1507    #[resource(prefix="a")]
1508    #[resource(ResourcePathSegmentKind::Path)]
1509    #[resource(ResourceStatePersistenceManager::Host)]
1510    #[resource(state(content::Binary))]
1511    pub struct Artifact();
1512
1513    #[resource(parents(Space,App))]
1514    #[resource(prefix="ub")]
1515    #[resource(ResourcePathSegmentKind::SkewerCase)]
1516    #[resource(ResourceStatePersistenceManager::Host)]
1517    pub struct UserBase();
1518
1519
1520    #[resource(parents(UserBase))]
1521    #[resource(prefix="u")]
1522    #[resource(ResourcePathSegmentKind::SkewerCase)]
1523    #[resource(ResourceStatePersistenceManager::Host)]
1524    pub struct User();
1525
1526
1527
1528    #[derive(Clone,Debug,Eq,PartialEq,Hash,Serialize,Deserialize)]
1529    pub enum DatabaseKind{
1530        Relational(Specific)
1531    }
1532
1533    #[derive(Clone,Debug,Eq,PartialEq,Hash,Serialize,Deserialize)]
1534    pub enum AuthenticatorKind{
1535        OpenId(Specific)
1536    }
1537
1538
1539    #[derive(Clone,Debug,Eq,PartialEq,Hash,Serialize,Deserialize)]
1540    pub enum FileKind{
1541        Directory,
1542        File
1543    }
1544
1545
1546    #[derive(Clone,Debug,Eq,PartialEq,Hash,Serialize,Deserialize)]
1547    pub enum ArtifactKind{
1548        Raw,
1549        AppConfig,
1550        MechtronConfig,
1551        BindConfig,
1552        Wasm,
1553    }
1554
1555    #[derive(Clone,Debug,Eq,PartialEq,Hash,Serialize,Deserialize)]
1556    pub enum CredsKind{
1557        Token,
1558        UsernamePassword
1559    }
1560
1561}
1562
1563
1564#[derive(Debug, Clone, Serialize, Deserialize)]
1565pub enum MetaSelector {
1566    None,
1567    Name(String),
1568    Label(LabelSelector),
1569}
1570
1571#[derive(Debug, Clone, Serialize, Deserialize)]
1572pub struct LabelSelector {
1573    pub labels: HashSet<LabelSelection>,
1574}
1575
1576impl ResourceSelector {
1577    pub fn new() -> Self {
1578        let fields = HashSet::new();
1579        ResourceSelector {
1580            meta: MetaSelector::None,
1581            fields: fields,
1582        }
1583    }
1584
1585    pub fn resource_types(&self) -> HashSet<ResourceType> {
1586        let mut rtn = HashSet::new();
1587        for field in &self.fields {
1588            if let FieldSelection::Type(resource_type) = field {
1589                rtn.insert(resource_type.clone());
1590            }
1591        }
1592        rtn
1593    }
1594
1595    pub fn add(&mut self, field: FieldSelection) {
1596        self.fields.retain(|f| !f.is_matching_kind(&field));
1597        self.fields.insert(field);
1598    }
1599
1600    pub fn is_empty(&self) -> bool {
1601        if !self.fields.is_empty() {
1602            return false;
1603        }
1604
1605        match &self.meta {
1606            MetaSelector::None => {
1607                return true;
1608            }
1609            MetaSelector::Name(_) => {
1610                return false;
1611            }
1612            MetaSelector::Label(labels) => {
1613                return labels.labels.is_empty();
1614            }
1615        };
1616    }
1617
1618    pub fn name(&mut self, name: String) -> Result<(), Error> {
1619        match &mut self.meta {
1620            MetaSelector::None => {
1621                self.meta = MetaSelector::Name(name.clone());
1622                Ok(())
1623            }
1624            MetaSelector::Name(_) => {
1625                self.meta = MetaSelector::Name(name.clone());
1626                Ok(())
1627            }
1628            MetaSelector::Label(_selector) => {
1629                Err("Selector is already set to a LABEL meta selector".into())
1630            }
1631        }
1632    }
1633
1634    pub fn add_label(&mut self, label: LabelSelection) -> Result<(), Error> {
1635        match &mut self.meta {
1636            MetaSelector::None => {
1637                self.meta = MetaSelector::Label(LabelSelector {
1638                    labels: HashSet::new(),
1639                });
1640                self.add_label(label)
1641            }
1642            MetaSelector::Name(_) => Err("Selector is already set to a NAME meta selector".into()),
1643            MetaSelector::Label(selector) => {
1644                selector.labels.insert(label);
1645                Ok(())
1646            }
1647        }
1648    }
1649
1650    pub fn add_field(&mut self, field: FieldSelection) {
1651        self.fields.insert(field);
1652    }
1653}
1654
1655#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
1656pub enum LabelSelection {
1657    Exact(Label),
1658}
1659
1660impl LabelSelection {
1661    pub fn exact(name: &str, value: &str) -> Self {
1662        LabelSelection::Exact(Label {
1663            name: name.to_string(),
1664            value: value.to_string(),
1665        })
1666    }
1667}
1668
1669#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
1670pub enum FieldSelection {
1671    Identifier(ResourceIdentifier),
1672    Type(ResourceType),
1673    Kind(ResourceKind),
1674    Specific(Specific),
1675    Owner(UserKey),
1676    Parent(ResourceIdentifier),
1677}
1678
1679
1680
1681impl ToString for FieldSelection {
1682    fn to_string(&self) -> String {
1683        match self {
1684            FieldSelection::Identifier(id) => id.to_string(),
1685            FieldSelection::Type(rt) => rt.to_string(),
1686            FieldSelection::Kind(kind) => kind.to_string(),
1687            FieldSelection::Specific(specific) => specific.to_string(),
1688            FieldSelection::Owner(owner) => owner.to_string(),
1689            FieldSelection::Parent(parent) => parent.to_string(),
1690        }
1691    }
1692}
1693
1694impl FieldSelection {
1695    pub fn is_matching_kind(&self, field: &FieldSelection) -> bool {
1696        match self {
1697            FieldSelection::Identifier(_) => {
1698                if let FieldSelection::Identifier(_) = field {
1699                    return true;
1700                }
1701            }
1702            FieldSelection::Type(_) => {
1703                if let FieldSelection::Type(_) = field {
1704                    return true;
1705                }
1706            }
1707            FieldSelection::Kind(_) => {
1708                if let FieldSelection::Kind(_) = field {
1709                    return true;
1710                }
1711            }
1712            FieldSelection::Specific(_) => {
1713                if let FieldSelection::Specific(_) = field {
1714                    return true;
1715                }
1716            }
1717            FieldSelection::Owner(_) => {
1718                if let FieldSelection::Owner(_) = field {
1719                    return true;
1720                }
1721            }
1722            FieldSelection::Parent(_) => {
1723                if let FieldSelection::Parent(_) = field {
1724                    return true;
1725                }
1726            }
1727        };
1728        return false;
1729    }
1730}
1731
1732
1733
1734#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
1735pub struct ResourceArchetype {
1736    pub kind: ResourceKind,
1737    pub specific: Option<Specific>,
1738    pub config: Option<ConfigSrc>,
1739}
1740
1741impl ResourceArchetype {
1742    pub fn from_resource_type(kind: ResourceKind) -> Self {
1743        ResourceArchetype {
1744            kind: kind,
1745            specific: Option::None,
1746            config: Option::None,
1747        }
1748    }
1749
1750    pub fn root() -> ResourceArchetype {
1751        ResourceArchetype {
1752            kind: ResourceKind::Root,
1753            specific: Option::None,
1754            config: Option::None,
1755        }
1756    }
1757
1758    pub fn valid(&self) -> Result<(), Fail> {
1759        if self.kind.resource_type() == ResourceType::Root {
1760            return Err(Fail::CannotCreateNothingResourceTypeItIsThereAsAPlaceholderDummy);
1761        }
1762        Ok(())
1763    }
1764}
1765
1766
1767
1768#[derive(Debug, Clone, Serialize, Deserialize)]
1769pub struct ResourceCreate {
1770    pub parent: ResourceIdentifier,
1771    pub key: KeyCreationSrc,
1772    pub address: AddressCreationSrc,
1773    pub archetype: ResourceArchetype,
1774    pub state_src: AssignResourceStateSrc<DataSet<BinSrc>>,
1775    pub registry_info: Option<ResourceRegistryInfo>,
1776    pub owner: Option<UserKey>,
1777    pub strategy: ResourceCreateStrategy,
1778    pub from: MessageFrom
1779}
1780
1781impl ResourceCreate {
1782    /*
1783    pub fn create(
1784        archetype: ResourceArchetype,
1785        state_src: AssignResourceStateSrc<DataSet<BinSrc>>,
1786    ) -> Self {
1787        ResourceCreate {
1788            parent: ResourceKey::Root.into(),
1789            key: KeyCreationSrc::None,
1790            address: AddressCreationSrc::None,
1791            archetype: archetype,
1792            state_src: state_src,
1793            registry_info: Option::None,
1794            owner: Option::None,
1795            strategy: ResourceCreateStrategy::Create,
1796        }
1797    }
1798     */
1799
1800    /*
1801    pub fn ensure_address(
1802        archetype: ResourceArchetype,
1803        src: AssignResourceStateSrc<DataSet<BinSrc>>,
1804    ) -> Self {
1805        ResourceCreate {
1806            parent: ResourceKey::Root.into(),
1807            key: KeyCreationSrc::None,
1808            address: AddressCreationSrc::None,
1809            archetype: archetype,
1810            state_src: src,
1811            registry_info: Option::None,
1812            owner: Option::None,
1813            strategy: ResourceCreateStrategy::Ensure,
1814        }
1815    }
1816     */
1817
1818    pub fn validate(&self) -> Result<(), Fail> {
1819        let resource_type = self.archetype.kind.resource_type();
1820
1821        self.archetype.valid()?;
1822
1823        if let KeyCreationSrc::Key(key) = &self.key {
1824            if key.resource_type() != resource_type {
1825                return Err(Fail::ResourceTypeMismatch("ResourceCreate: key: KeyCreationSrc::Key(key) resource type != init.archetype.kind.resource_type()".into()));
1826            }
1827        }
1828
1829        Ok(())
1830    }
1831
1832
1833
1834    pub fn keyed_or(self, message: &str) -> Result<Self, Error> {
1835        if self.parent.is_key() {
1836            return Ok(self);
1837        } else {
1838            Err(message.into())
1839        }
1840    }
1841}
1842
1843
1844
1845#[derive(Debug, Clone, Serialize, Deserialize)]
1846pub enum ResourceStatus {
1847    Unknown,
1848    Preparing,
1849    Ready,
1850}
1851
1852impl ToString for ResourceStatus {
1853    fn to_string(&self) -> String {
1854        match self {
1855            Self::Unknown => "Unknown".to_string(),
1856            Self::Preparing => "Preparing".to_string(),
1857            Self::Ready => "Ready".to_string(),
1858        }
1859    }
1860}
1861
1862impl FromStr for ResourceStatus {
1863    type Err = Error;
1864
1865    fn from_str(s: &str) -> Result<Self, Self::Err> {
1866        match s {
1867            "Unknown" => Ok(Self::Unknown),
1868            "Preparing" => Ok(Self::Preparing),
1869            "Ready" => Ok(Self::Ready),
1870            what => Err(format!("not recognized: {}", what).into()),
1871        }
1872    }
1873}
1874
1875#[derive(Debug, Clone, Serialize, Deserialize)]
1876pub enum AddressCreationSrc {
1877    Append(String),
1878    Just(String),
1879    Exact(ResourcePath),
1880}
1881
1882#[derive(Debug, Clone, Serialize, Deserialize)]
1883pub enum KeyCreationSrc {
1884    None,
1885    Key(ResourceKey),
1886}
1887
1888#[derive(Clone, Serialize, Deserialize)]
1889pub enum KeySrc {
1890    None,
1891    Key(ResourceKey),
1892    Address(ResourceAddress),
1893}
1894
1895/// can have other options like to Initialize the state data
1896#[derive(Debug, Clone, Serialize, Deserialize, strum_macros::Display)]
1897pub enum AssignResourceStateSrc<DATASET> {
1898    Stateless,
1899    Direct(DATASET),
1900    CreateArgs(String),
1901}
1902
1903impl TryInto<LocalStateSetSrc> for AssignResourceStateSrc<DataSet<BinSrc>> {
1904    type Error = Error;
1905
1906    fn try_into(self) -> Result<LocalStateSetSrc, Self::Error> {
1907        match self {
1908            AssignResourceStateSrc::Direct(state) => Ok(LocalStateSetSrc::Some(state.try_into()?)),
1909            AssignResourceStateSrc::Stateless => Ok(LocalStateSetSrc::None),
1910            _ => Err(format!("cannot turn {}", self.to_string()).into()),
1911        }
1912    }
1913}
1914
1915#[derive(Debug, Clone, Serialize, Deserialize)]
1916pub struct ResourceStub {
1917    pub key: ResourceKey,
1918    pub address: ResourcePath,
1919    pub archetype: ResourceArchetype,
1920    pub owner: Option<UserKey>,
1921}
1922
1923impl ResourceStub {
1924    pub fn root() -> ResourceStub {
1925        ResourceStub {
1926            key: ResourceKey::Root,
1927            address: ResourcePath::root(),
1928            archetype: ResourceArchetype::root(),
1929            owner: Option::None,
1930        }
1931    }
1932}
1933
1934
1935
1936impl From<Resource> for ResourceStub {
1937    fn from(resource: Resource) -> Self {
1938        ResourceStub {
1939            key: resource.key,
1940            address: resource.address,
1941            archetype: resource.archetype,
1942            owner: resource.owner,
1943        }
1944    }
1945}
1946
1947impl ResourceStub {
1948    pub fn validate(&self, resource_type: ResourceType) -> bool {
1949        self.key.resource_type() == resource_type
1950        && self.archetype.kind.resource_type() == resource_type
1951    }
1952}
1953
1954#[derive(Debug, Clone, Serialize, Deserialize)]
1955pub enum AssignKind {
1956    Create,
1957    // eventually we want to allow for Assignments where things are 'Moved' as well
1958}
1959
1960#[derive(Debug, Clone, Serialize, Deserialize)]
1961pub enum ResourceAction<S> {
1962    Create(ResourceAssign<S>),
1963    Update(Resource)
1964}
1965
1966#[derive(Debug, Clone, Serialize, Deserialize)]
1967pub struct ResourceAssign<S> {
1968    pub kind: AssignKind,
1969    pub stub: ResourceStub,
1970    pub state_src: S,
1971}
1972
1973impl<S> ResourceAssign<S> {
1974    pub fn key(&self) -> ResourceKey {
1975        self.stub.key.clone()
1976    }
1977
1978    pub fn archetype(&self) -> ResourceArchetype {
1979        self.stub.archetype.clone()
1980    }
1981}
1982
1983#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
1984pub enum ResourcePropertyKey {
1985    State
1986}
1987
1988#[derive(Debug, Clone, Serialize, Deserialize)]
1989pub enum ResourceProperty{
1990    State(DataSet<BinSrc>)
1991}
1992
1993#[derive(Debug, Clone, Serialize, Deserialize)]
1994pub struct Resource {
1995    pub key: ResourceKey,
1996    pub address: ResourcePath,
1997    pub archetype: ResourceArchetype,
1998    pub state: DataSet<BinSrc>,
1999    pub owner: Option<UserKey>,
2000}
2001
2002impl Resource {
2003    pub fn new(
2004        key: ResourceKey,
2005        address: ResourcePath,
2006        archetype: ResourceArchetype,
2007        state_src: DataSet<BinSrc>,
2008    ) -> Resource {
2009        Resource {
2010            key: key,
2011            address: address,
2012            state: state_src,
2013            archetype: archetype,
2014            owner: Option::None, // fix later
2015        }
2016    }
2017
2018    pub fn key(&self) -> ResourceKey {
2019        self.key.clone()
2020    }
2021
2022    pub fn address(&self) -> ResourcePath {
2023        self.address.clone()
2024    }
2025
2026    pub fn resource_type(&self) -> ResourceType {
2027        self.key.resource_type()
2028    }
2029
2030    pub fn state_src(&self) -> DataSet<BinSrc> {
2031        self.state.clone()
2032    }
2033}
2034
2035impl From<DataSet<BinSrc>> for LocalStateSetSrc {
2036    fn from(src: DataSet<BinSrc>) -> Self {
2037        LocalStateSetSrc::Some(src)
2038    }
2039}
2040
2041#[derive(Clone)]
2042pub enum LocalStateSetSrc {
2043    None,
2044    Some(DataSet<BinSrc>),
2045    AlreadyHosted,
2046}
2047
2048#[derive(Clone, Serialize, Deserialize)]
2049pub enum RemoteDataSrc {
2050    None,
2051    Memory(Arc<Vec<u8>>),
2052}
2053
2054#[derive(Debug, Clone, Serialize, Deserialize)]
2055pub enum ResourceCreateStrategy {
2056    Create,
2057    CreateOrUpdate,
2058    Ensure,
2059}
2060
2061#[derive(Debug, Clone, Serialize, Deserialize)]
2062pub enum Unique {
2063    Sequence,
2064    Index,
2065}
2066
2067#[derive(Debug, Clone, Serialize, Deserialize)]
2068pub struct ResourceSelector {
2069    pub meta: MetaSelector,
2070    pub fields: HashSet<FieldSelection>,
2071}
2072
2073impl ResourceSelector {
2074    pub fn children_selector(parent: ResourceIdentifier) -> Self {
2075        let mut selector = Self::new();
2076        selector.add_field(FieldSelection::Parent(parent));
2077        selector
2078    }
2079
2080    pub fn children_of_type_selector(parent: ResourceIdentifier, child_type: ResourceType) -> Self {
2081        let mut selector = Self::new();
2082        selector.add_field(FieldSelection::Parent(parent));
2083        selector.add_field(FieldSelection::Type(child_type));
2084        selector
2085    }
2086
2087    pub fn app_selector() -> Self {
2088        let mut selector = Self::new();
2089        selector.add_field(FieldSelection::Type(ResourceType::App));
2090        selector
2091    }
2092}
2093
2094#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
2095pub enum ConfigSrc {
2096    None,
2097    Artifact(ResourcePath)
2098}
2099
2100impl ToString for ConfigSrc {
2101    fn to_string(&self) -> String {
2102        match self {
2103            ConfigSrc::None => {
2104                "None".to_string()
2105            }
2106            ConfigSrc::Artifact(address) => {
2107                address.to_string()
2108            }
2109        }
2110    }
2111}
2112
2113impl FromStr for ConfigSrc {
2114    type Err = Error;
2115
2116    fn from_str(s: &str) -> Result<Self, Self::Err> {
2117        if "None" == s {
2118            Ok(Self::None)
2119        } else {
2120            let path= ResourcePath::from_str(s)?;
2121            Ok(Self::Artifact(path))
2122        }
2123    }
2124}
2125
2126#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
2127pub struct Label {
2128    pub name: String,
2129    pub value: String,
2130}
2131
2132#[derive(Clone, Serialize, Deserialize)]
2133pub struct LabelConfig {
2134    pub name: String,
2135    pub index: bool,
2136}
2137
2138#[derive(Debug, Clone, Serialize, Deserialize)]
2139pub struct ResourceRegistryInfo {
2140    pub names: Names,
2141    pub labels: Labels,
2142}
2143
2144impl ResourceRegistryInfo {
2145    pub fn new() -> Self {
2146        ResourceRegistryInfo {
2147            names: Names::new(),
2148            labels: Labels::new(),
2149        }
2150    }
2151}
2152
2153pub type Labels = HashMap<String, String>;
2154pub type Names = Vec<String>;
2155
2156impl From<&str> for Fail {
2157    fn from(str: &str) -> Self {
2158        Fail::Error(str.to_string())
2159    }
2160}
2161impl From<String> for Fail {
2162    fn from(str: String) -> Self {
2163        Fail::Error(str)
2164    }
2165}
2166
2167
2168impl From<()> for Fail {
2169    fn from(_error: ()) -> Self {
2170        Fail::Error("() From Error".to_string())
2171    }
2172}
2173
2174impl From<std::io::Error> for Fail {
2175    fn from(error: std::io::Error) -> Self {
2176        Fail::Error(error.to_string())
2177    }
2178}
2179
2180impl From<SemVerError> for Fail {
2181    fn from(error: SemVerError) -> Self {
2182        Fail::Error(error.to_string())
2183    }
2184}
2185
2186impl ResourcePath {
2187    pub fn new( segments: Vec<String> ) -> Self {
2188        Self{
2189            segments
2190        }
2191    }
2192
2193    pub fn parent(&self) -> Option<Self> {
2194        if self.segments.is_empty() {
2195            Option::None
2196        } else {
2197            let mut segments = self.segments.clone();
2198            segments.remove( segments.len() -1 );
2199            Option::Some( ResourcePath::new(segments) )
2200        }
2201    }
2202
2203    pub fn name(&self)->String {
2204        if self.segments.is_empty() {
2205            "".to_string()
2206        } else {
2207            self.segments.last().unwrap().to_string()
2208        }
2209    }
2210}
2211
2212#[derive(Debug,Clone,Serialize,Deserialize,Eq,PartialEq,Hash)]
2213pub struct ResourcePathAndType {
2214    pub path: ResourcePath,
2215    pub resource_type: ResourceType,
2216}
2217
2218impl ResourcePathAndType {
2219    pub fn root()-> Self {
2220        Self {
2221            path: ResourcePath::new(vec![]),
2222            resource_type: ResourceType::Root
2223        }
2224    }
2225
2226    pub fn parent(&self) -> Option<ResourcePath> {
2227        self.path.parent()
2228    }
2229
2230    pub fn name(&self) -> String {
2231        self.path.name()
2232    }
2233
2234    pub fn resource_type(&self) -> ResourceType {
2235        self.resource_type.clone()
2236    }
2237}
2238
2239impl FromStr for ResourcePathAndType {
2240    type Err = Error;
2241
2242    fn from_str(s: &str) -> Result<Self, Self::Err> {
2243        let (leftover,result) = parse::parse_resource_path_and_type(s)?;
2244
2245        if !leftover.is_empty() {
2246            return Err(format!("illegal resource path with type: '{}' unrecognized portion: '{}'",s, leftover).into());
2247        }
2248
2249        Ok(result?)
2250    }
2251}
2252
2253impl ToString for ResourcePathAndType{
2254    fn to_string(&self) -> String {
2255        match self.resource_type.requires_kind() {
2256            true => {
2257                format!("{}<{}<?>>",self.path.to_string(),self.resource_type.to_string())
2258            },
2259            false => {
2260
2261                format!("{}<{}>",self.path.to_string(),self.resource_type.to_string())
2262            }
2263        }
2264    }
2265}
2266
2267#[derive(Debug,Clone,Serialize,Deserialize,Eq,PartialEq,Hash)]
2268pub struct ResourcePathAndKind {
2269    pub path: ResourcePath,
2270    pub kind: ResourceKind,
2271}
2272
2273impl ResourcePathAndKind {
2274    pub fn new(path: ResourcePath, kind: ResourceKind) -> Result<Self,Error> {
2275        let path_segment_kind: ResourcePathSegmentKind = kind.resource_type().path_segment_kind();
2276        // if the path segment is illegal then there will be a Result::Err returned
2277        path_segment_kind.from_str(path.segments.last().ok_or("expected at least one resource path segment" )?.as_str() )?;
2278
2279        Ok(ResourcePathAndKind{
2280            path,
2281            kind
2282        })
2283    }
2284
2285    pub fn parent(&self) -> Option<ResourcePath> {
2286        self.path.parent()
2287    }
2288}
2289
2290impl FromStr for ResourcePathAndKind {
2291    type Err = Error;
2292
2293    fn from_str(s: &str) -> Result<Self, Self::Err> {
2294        let (leftover,result) = parse::parse_resource_path_and_kind(s)?;
2295
2296        if !leftover.is_empty() {
2297            return Err(format!("illegal resource path with kind: '{}' unrecognized portion: '{}'",s, leftover).into());
2298        }
2299
2300        Ok(result?)
2301    }
2302}
2303
2304impl ToString for ResourcePathAndKind {
2305    fn to_string(&self) -> String {
2306        format!("{}{}",self.path.to_string(),self.kind.to_string())
2307    }
2308}
2309
2310#[derive(Debug,Clone,Serialize,Deserialize,Eq,PartialEq,Hash)]
2311pub struct ResourcePath {
2312  pub segments: Vec<String>
2313}
2314
2315impl ResourcePath {
2316    pub fn root() -> Self {
2317        ResourcePath {
2318            segments: vec!()
2319        }
2320    }
2321
2322    pub fn is_root(&self) -> bool {
2323        self.segments.is_empty()
2324    }
2325    pub fn append(&self, s: &str) -> Result<ResourcePath,Error> {
2326        ResourcePath::from_str(format!("{}:{}", self.to_string(), s).as_str())
2327    }
2328}
2329
2330impl ToString for ResourcePath {
2331    fn to_string(&self) -> String {
2332            let mut rtn = String::new();
2333            for i in 0..self.segments.len() {
2334                let segment = self.segments.get(i).unwrap();
2335                rtn.push_str( segment.to_string().as_str() );
2336                if i < self.segments.len()-1 {
2337                    rtn.push_str(":");
2338                }
2339            }
2340            rtn
2341    }
2342}
2343
2344impl FromStr for ResourcePath {
2345    type Err = Error;
2346
2347    fn from_str(s: &str) -> Result<Self, Self::Err> {
2348        let (leftover,path) = parse::parse_resource_path(s)?;
2349        if !leftover.is_empty() {
2350            return Err(format!("illegal resource path: '{}' unrecognized portion: '{}'",s, leftover).into());
2351        }
2352        Ok(path)
2353    }
2354}
2355
2356impl Into<ResourcePath> for ResourcePathAndKind {
2357    fn into(self) -> ResourcePath {
2358        self.path
2359    }
2360}