cosmic_space/
loc.rs

1use core::fmt::Formatter;
2use core::str::FromStr;
3use std::collections::HashMap;
4use std::ops::{Deref, DerefMut};
5
6use convert_case::{Case, Casing};
7use nom::combinator::all_consuming;
8use serde::de::{Error, Visitor};
9use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
10
11use cosmic_nom::{new_span, Trace, Tw};
12
13use crate::err::ParseErrs;
14use crate::hyper::ChildRegistry;
15use crate::kind::KindParts;
16use crate::log::{SpanLogger, Trackable};
17use crate::parse::error::result;
18use crate::parse::{
19    CamelCase, consume_point, consume_point_ctx, Domain, Env,
20    kind_parts, parse_star_key, point_and_kind, point_route_segment, point_selector, point_var, ResolverErr,
21    SkewerCase,
22};
23use crate::particle::traversal::TraversalPlan;
24use crate::selector::{Pattern, Selector, SpecificSelector, VersionReq};
25use crate::util::{ToResolved, uuid, ValueMatcher, ValuePattern};
26use crate::wave::exchange::asynch::Exchanger;
27use crate::wave::{
28    DirectedWave, Ping, Pong, Recipients, ReflectedWave, SingularDirectedWave, ToRecipients,
29    UltraWave, Wave,
30};
31use crate::Agent::Anonymous;
32use crate::{Agent, ANONYMOUS, BaseKind, HYPERUSER, Kind, KindTemplate, ParticleRecord, SpaceErr};
33use crate::point::{Point, PointDef, PointSeg, PointSegCtx, PointSegKind, PointSegPairDef, PointSegVar, RouteSeg, RouteSegVar};
34
35lazy_static! {
36    pub static ref CENTRAL: Point = StarKey::central().to_point();
37    pub static ref GLOBAL_LOGGER: Point = Point::from_str("GLOBAL::logger").unwrap();
38    pub static ref GLOBAL_REGISTRY: Point = Point::from_str("GLOBAL::registry").unwrap();
39    pub static ref GLOBAL_EXEC: Point = Point::from_str("GLOBAL::executor").unwrap();
40    pub static ref LOCAL_STAR: Point = Point::from_str("LOCAL::star").unwrap();
41    pub static ref LOCAL_PORTAL: Point = Point::from_str("LOCAL::portal").unwrap();
42    pub static ref LOCAL_HYPERGATE: Point = Point::from_str("LOCAL::hypergate").unwrap();
43    pub static ref LOCAL_ENDPOINT: Point = Point::from_str("LOCAL::endpoint").unwrap();
44    pub static ref REMOTE_ENDPOINT: Point = Point::from_str("REMOTE::endpoint").unwrap();
45    pub static ref STD_WAVE_TRAVERSAL_PLAN: TraversalPlan =
46        TraversalPlan::new(vec![Layer::Field, Layer::Shell, Layer::Core]);
47    pub static ref MECHTRON_WAVE_TRAVERSAL_PLAN: TraversalPlan = TraversalPlan::new(vec![
48        Layer::Field,
49        Layer::Shell,
50        Layer::Portal,
51        Layer::Host,
52        Layer::Guest,
53        Layer::Core
54    ]);
55    pub static ref PORTAL_WAVE_TRAVERSAL_PLAN: TraversalPlan = TraversalPlan::new(vec![
56        Layer::Field,
57        Layer::Shell,
58        Layer::Portal,
59        Layer::Host,
60        Layer::Guest,
61        Layer::Core
62    ]);
63    pub static ref CONTROL_WAVE_TRAVERSAL_PLAN: TraversalPlan = TraversalPlan::new(vec![
64        Layer::Field,
65        Layer::Shell,
66        Layer::Portal,
67        Layer::Host,
68        Layer::Guest,
69        Layer::Core
70    ]);
71    pub static ref STAR_WAVE_TRAVERSAL_PLAN: TraversalPlan =
72        TraversalPlan::new(vec![Layer::Field, Layer::Shell, Layer::Core]);
73}
74
75pub trait ToBaseKind {
76    fn to_base(&self) -> BaseKind;
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
80pub struct Uuid {
81    uuid: String,
82}
83
84impl Uuid {
85    pub fn rnd() -> Self {
86        //Self::new( uuid::Uuid::new_v4() )
87        uuid()
88    }
89    /*
90    pub fn new(uuid: uuid::Uuid) -> Self {
91        Self {
92            uuid: uuid.to_string()
93        }
94    }
95     */
96
97    pub fn from<S: ToString>(uuid: S) -> Result<Self, SpaceErr> {
98        //Ok(Self::new(uuid::Uuid::from_str(uuid.to_string().as_str()).map_err(|e| UniErr::server_error(format!("'{}' is not a valid uuid",uuid.to_string())))?))
99        Ok(Self {
100            uuid: uuid.to_string(),
101        })
102    }
103
104    pub fn from_unwrap<S: ToString>(uuid: S) -> Self {
105        Self {
106            uuid: uuid.to_string(),
107        }
108    }
109}
110
111impl ToString for Uuid {
112    fn to_string(&self) -> String {
113        self.uuid.clone()
114    }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, strum_macros::Display)]
118pub enum ProvisionAffinity {
119    Local,
120    Wrangle,
121}
122
123pub type Meta = HashMap<String, String>;
124pub type HostKey = String;
125
126#[derive(Debug, Clone, Eq, PartialEq, Hash)]
127pub struct Version {
128    pub version: semver::Version,
129}
130
131impl Deref for Version {
132    type Target = semver::Version;
133
134    fn deref(&self) -> &Self::Target {
135        &self.version
136    }
137}
138
139impl Serialize for Version {
140    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
141    where
142        S: Serializer,
143    {
144        serializer.serialize_str(self.version.to_string().as_str())
145    }
146}
147
148struct VersionVisitor;
149
150impl<'de> Visitor<'de> for VersionVisitor {
151    type Value = Version;
152
153    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
154        formatter.write_str("SemVer version")
155    }
156
157    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
158    where
159        E: de::Error,
160    {
161        match Version::from_str(v) {
162            Ok(version) => Ok(version),
163            Err(error) => {
164                //Err(de::Error::custom(error.to_string() ))
165                Err(de::Error::invalid_type(de::Unexpected::Str(v), &self))
166            }
167        }
168    }
169}
170
171impl<'de> Deserialize<'de> for Version {
172    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173    where
174        D: Deserializer<'de>,
175    {
176        deserializer.deserialize_str(VersionVisitor)
177    }
178}
179
180impl ToString for Version {
181    fn to_string(&self) -> String {
182        self.version.to_string()
183    }
184}
185
186impl TryInto<semver::Version> for Version {
187    type Error = SpaceErr;
188
189    fn try_into(self) -> Result<semver::Version, Self::Error> {
190        Ok(self.version)
191    }
192}
193
194impl FromStr for Version {
195    type Err = SpaceErr;
196
197    fn from_str(s: &str) -> Result<Self, Self::Err> {
198        let version = semver::Version::from_str(s)?;
199        Ok(Self { version })
200    }
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
204pub struct Variable {
205    pub name: String,
206    pub trace: Trace,
207}
208
209impl Variable {
210    pub fn new(name: String, trace: Trace) -> Self {
211        Self { name, trace }
212    }
213}
214
215pub enum VarVal<V> {
216    Var(Tw<SkewerCase>),
217    Val(Tw<V>),
218}
219
220impl<V> ToResolved<V> for VarVal<V>
221where
222    V: FromStr<Err = SpaceErr>,
223{
224    fn to_resolved(self, env: &Env) -> Result<V, SpaceErr> {
225        match self {
226            VarVal::Var(var) => match env.val(var.as_str()) {
227                Ok(val) => {
228                    let val: String = val.clone().try_into()?;
229                    Ok(V::from_str(val.as_str())?)
230                }
231                Err(err) => {
232                    let trace = var.trace.clone();
233                    match err {
234                        ResolverErr::NotAvailable => Err(ParseErrs::from_range(
235                            "variables not available in this context",
236                            "variables not available",
237                            trace.range,
238                            trace.extra,
239                        )),
240                        ResolverErr::NotFound => Err(ParseErrs::from_range(
241                            format!("variable '{}' not found", var.unwrap().to_string()).as_str(),
242                            "not found",
243                            trace.range,
244                            trace.extra,
245                        )),
246                    }
247                }
248            },
249            VarVal::Val(val) => Ok(val.unwrap()),
250        }
251    }
252}
253
254pub trait RouteSegQuery {
255    fn is_local(&self) -> bool;
256    fn is_global(&self) -> bool;
257}
258
259pub trait PointSegQuery {
260    fn is_filesystem_root(&self) -> bool;
261    fn kind(&self) -> PointSegKind;
262}
263
264pub trait PointSegment {}
265
266pub type PointSegPair = PointSegPairDef<PointSeg>;
267
268#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
269pub enum Topic {
270    None,
271    Not,
272    Any,
273    Cli,
274    Uuid(Uuid),
275    Path(Vec<SkewerCase>),
276}
277
278impl ToString for Topic {
279    fn to_string(&self) -> String {
280        match self {
281            Topic::None => "".to_string(),
282            Topic::Not => "Topic<!>".to_string(),
283            Topic::Any => "Topic<*>".to_string(),
284            Topic::Uuid(uuid) => format!("Topic<Uuid>({})", uuid.to_string()),
285            Topic::Path(segs) => {
286                let segments: Vec<String> = segs.into_iter().map(|s| s.to_string()).collect();
287                let mut rtn = String::new();
288                for (index, segment) in segments.iter().enumerate() {
289                    rtn.push_str(segment.as_str());
290                    if index < segments.len() - 1 {
291                        rtn.push_str(":")
292                    }
293                }
294                return format!("Topic<Path>({})", rtn);
295            }
296            Topic::Cli => "Topic<Cli>".to_string(),
297        }
298    }
299}
300
301impl Topic {
302    pub fn uuid() -> Self {
303        Topic::Uuid(Uuid::rnd())
304    }
305}
306
307impl ValueMatcher<Topic> for Topic {
308    fn is_match(&self, x: &Topic) -> Result<(), ()> {
309        if *x == *self {
310            Ok(())
311        } else {
312            Err(())
313        }
314    }
315}
316
317#[derive(
318    Debug,
319    Clone,
320    Serialize,
321    Deserialize,
322    Eq,
323    PartialEq,
324    Hash,
325    strum_macros::Display,
326    strum_macros::EnumString,
327    Ordinalize,
328)]
329#[repr(u8)]
330pub enum Layer {
331    Gravity = 0,
332    Field,
333    Shell,
334    Portal,
335    Host,
336    Guest,
337    Core,
338}
339
340impl Layer {
341    pub fn has_state(&self) -> bool {
342        match self {
343            Layer::Gravity => false,
344            Layer::Field => true,
345            Layer::Shell => true,
346            Layer::Portal => false,
347            Layer::Host => false,
348            Layer::Guest => false,
349            Layer::Core => false,
350        }
351    }
352}
353
354impl Default for Layer {
355    fn default() -> Self {
356        Layer::Core
357    }
358}
359
360impl Default for Topic {
361    fn default() -> Self {
362        Topic::None
363    }
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
367pub struct Surface {
368    pub point: Point,
369    pub layer: Layer,
370    pub topic: Topic,
371}
372
373impl Surface {
374    pub fn new(point: Point, layer: Layer, topic: Topic) -> Self {
375        Self {
376            point,
377            layer,
378            topic,
379        }
380    }
381
382    fn postfix(&self) -> String {
383        let point = self.clone().to_point();
384        match &self.topic {
385            Topic::None => {
386                format!("{}@{}", self.point.postfix(), self.layer.to_string())
387            }
388            topic => {
389                format!(
390                    "{}@{}+{}",
391                    self.point.postfix(),
392                    self.layer.to_string(),
393                    topic.to_string()
394                )
395            }
396        }
397    }
398}
399
400impl Into<Recipients> for Surface {
401    fn into(self) -> Recipients {
402        Recipients::Single(self)
403    }
404}
405
406impl ToRecipients for Surface {
407    fn to_recipients(self) -> Recipients {
408        Recipients::Single(self)
409    }
410}
411
412impl ToString for Surface {
413    fn to_string(&self) -> String {
414        let point = self.clone().to_point();
415        match &self.topic {
416            Topic::None => {
417                format!("{}@{}", self.point.to_string(), self.layer.to_string())
418            }
419            topic => {
420                format!(
421                    "{}@{}+{}",
422                    self.point.to_string(),
423                    self.layer.to_string(),
424                    topic.to_string()
425                )
426            }
427        }
428    }
429}
430
431#[derive(Clone, Serialize, Deserialize)]
432pub struct SurfaceSelector {
433    pub point: ValuePattern<Point>,
434    pub topic: ValuePattern<Topic>,
435    pub layer: ValuePattern<Layer>,
436}
437
438impl Into<SurfaceSelector> for Surface {
439    fn into(self) -> SurfaceSelector {
440        let point = ValuePattern::Pattern(self.point);
441        let topic = match self.topic {
442            Topic::None => ValuePattern::Any,
443            Topic::Not => ValuePattern::None,
444            Topic::Any => ValuePattern::Any,
445            Topic::Uuid(uuid) => ValuePattern::Pattern(Topic::Uuid(uuid)),
446            Topic::Path(path) => ValuePattern::Pattern(Topic::Path(path)),
447            Topic::Cli => ValuePattern::Pattern(Topic::Cli),
448        };
449        let layer = ValuePattern::Pattern(self.layer);
450        SurfaceSelector {
451            point,
452            topic,
453            layer,
454        }
455    }
456}
457
458impl ValueMatcher<Surface> for SurfaceSelector {
459    fn is_match(&self, surface: &Surface) -> Result<(), ()> {
460        match &self.point {
461            ValuePattern::Any => {}
462            ValuePattern::None => return Err(()),
463            ValuePattern::Pattern(point) if *point != surface.point => return Err(()),
464            _ => {}
465        }
466
467        match &self.layer {
468            ValuePattern::Any => {}
469            ValuePattern::None => return Err(()),
470            ValuePattern::Pattern(layer) if *layer != surface.layer => return Err(()),
471            _ => {}
472        }
473
474        match &self.topic {
475            ValuePattern::Any => {}
476            ValuePattern::None => return Err(()),
477            ValuePattern::Pattern(topic) if *topic != surface.topic => return Err(()),
478            _ => {}
479        }
480
481        Ok(())
482    }
483}
484
485impl Surface {
486    pub fn with_topic(&self, topic: Topic) -> Self {
487        Self {
488            point: self.point.clone(),
489            layer: self.layer.clone(),
490            topic,
491        }
492    }
493
494    pub fn with_layer(&self, layer: Layer) -> Self {
495        Self {
496            point: self.point.clone(),
497            layer,
498            topic: self.topic.clone(),
499        }
500    }
501}
502
503impl Deref for Surface {
504    type Target = Point;
505
506    fn deref(&self) -> &Self::Target {
507        &self.point
508    }
509}
510
511impl ToPoint for Surface {
512    fn to_point(&self) -> Point {
513        self.point.clone()
514    }
515}
516
517impl ToSurface for Surface {
518    fn to_surface(&self) -> Surface {
519        self.clone()
520    }
521}
522
523pub trait ToPoint {
524    fn to_point(&self) -> Point;
525}
526
527pub trait ToSurface {
528    fn to_surface(&self) -> Surface;
529}
530
531pub type MachineName = String;
532pub type ConstellationName = String;
533
534#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Debug, Clone, Serialize, Deserialize)]
535pub struct StarKey {
536    pub constellation: ConstellationName,
537    pub name: String,
538    pub index: u16,
539}
540
541impl StarKey {
542    pub fn sql_name(&self) -> String {
543        format!(
544            "star_{}_{}_{}",
545            self.constellation.to_lowercase().replace("-", "_"),
546            self.name.to_lowercase().replace("-", "_"),
547            self.index
548        )
549    }
550}
551
552impl Into<Point> for StarKey {
553    fn into(self) -> Point {
554        self.to_point()
555    }
556}
557
558impl Into<Surface> for StarKey {
559    fn into(self) -> Surface {
560        self.to_surface()
561    }
562}
563
564impl TryFrom<Point> for StarKey {
565    type Error = SpaceErr;
566
567    fn try_from(point: Point) -> Result<Self, Self::Error> {
568        match point.route {
569            RouteSeg::Star(star) => StarKey::from_str(star.as_str()),
570            _ => Err("can only extract StarKey from Mesh point routes".into()),
571        }
572    }
573}
574
575impl ToPoint for StarKey {
576    fn to_point(&self) -> Point {
577        Point::from_str(format!("<<{}>>::star", self.to_string()).as_str()).unwrap()
578    }
579}
580
581impl ToSurface for StarKey {
582    fn to_surface(&self) -> Surface {
583        self.clone().to_point().to_surface()
584    }
585}
586
587pub struct StarHandle {
588    pub name: String,
589    pub index: u16,
590}
591
592impl StarHandle {
593    pub fn name<S: ToString>(name: S) -> Self {
594        Self {
595            name: name.to_string(),
596            index: 0,
597        }
598    }
599
600    pub fn new<S: ToString>(name: S, index: u16) -> Self {
601        Self {
602            name: name.to_string(),
603            index,
604        }
605    }
606}
607
608impl StarKey {
609    pub fn new(constellation: &ConstellationName, handle: &StarHandle) -> Self {
610        Self {
611            constellation: constellation.clone(),
612            name: handle.name.clone(),
613            index: handle.index.clone(),
614        }
615    }
616
617    pub fn machine(machine_name: MachineName) -> Self {
618        StarKey::new(
619            &"machine".to_string(),
620            &StarHandle::name(machine_name.as_str()),
621        )
622    }
623
624    pub fn central() -> Self {
625        StarKey {
626            constellation: "central".to_string(),
627            name: "central".to_string(),
628            index: 0,
629        }
630    }
631}
632
633impl ToString for StarKey {
634    fn to_string(&self) -> String {
635        format!("STAR::{}:{}[{}]", self.constellation, self.name, self.index)
636    }
637}
638
639impl StarKey {
640    pub fn to_sql_name(&self) -> String {
641        format!("STAR::{}_{}_{}", self.constellation, self.name, self.index)
642    }
643}
644
645impl FromStr for StarKey {
646    type Err = SpaceErr;
647
648    fn from_str(s: &str) -> Result<Self, Self::Err> {
649        Ok(result(all_consuming(parse_star_key)(new_span(s)))?)
650    }
651}
652
653#[async_trait]
654pub trait PointFactory: Send + Sync {
655    async fn create(&self) -> Result<Point, SpaceErr>;
656}
657
658#[cfg(test)]
659pub mod test {
660    use crate::point::Point;
661    use core::str::FromStr;
662
663    #[test]
664    pub fn test_root_routes() {
665        let point = Point::from_str("GLOBAL::star").unwrap();
666        let parent = point.parent().unwrap();
667        assert!(!parent.is_local_root());
668        assert_eq!(parent.to_string(), "GLOBAL::ROOT".to_string())
669    }
670
671    #[test]
672    pub fn test_push_fs() {
673        let point = Point::from_str("repo:some:1.0.0:/blah").unwrap();
674        let bundle = point.to_bundle().unwrap();
675        println!("{}", bundle.to_string());
676        let root = bundle.clone().push(":/").unwrap();
677        println!("{}", root.to_string());
678    }
679}