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#[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 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 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
185pub 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
422fn 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
553pub 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#[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 }
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(), },
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 }
1369
1370impl ResourceIdentifier {
1371 }
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
1400impl 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 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#[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 }
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, }
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 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}