1use core::str::FromStr;
2use nom::ExtendInto;
3use std::collections::HashMap;
4use std::ops::{Deref, DerefMut};
5use std::sync::Arc;
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use cosmic_macros_primitive::Autobox;
11use cosmic_nom::Tw;
12
13use crate::command::{Command, RawCommand};
14use crate::err::ParseErrs;
15use crate::hyper::{Greet, HyperSubstance, Knock, ParticleLocation};
16use crate::loc::Meta;
17use crate::log::{AuditLog, Log, LogSpan, LogSpanEvent, PointlessLog};
18use crate::parse::model::Subst;
19use crate::parse::Env;
20use crate::particle::Particle;
21use crate::util::{ToResolved, ValueMatcher, ValuePattern};
22use crate::wave::core::cmd::CmdMethod;
23use crate::wave::core::ext::ExtMethod;
24use crate::wave::core::http2::HttpMethod;
25use crate::wave::core::hyp::HypMethod;
26use crate::wave::core::{DirectedCore, HeaderMap, ReflectedCore};
27use crate::wave::{Pong, UltraWave};
28use crate::{Details, SpaceErr, Status, Stub, Surface, util};
29use url::Url;
30use crate::point::{Point, PointCtx, PointVar};
31
32#[derive(
33 Debug,
34 Clone,
35 Serialize,
36 Deserialize,
37 Eq,
38 PartialEq,
39 strum_macros::Display,
40 strum_macros::EnumString,
41)]
42pub enum SubstanceKind {
43 Empty,
44 List,
45 Map,
46 Point,
47 Surface,
48 Text,
49 Boolean,
50 Int,
51 Meta,
52 Bin,
53 Stub,
54 Details,
55 Status,
56 Particle,
57 Location,
58 FormErrs,
59 Json,
60 MultipartForm,
61 RawCommand,
62 Command,
63 DirectedCore,
64 ReflectedCore,
65 Hyp,
66 Token,
67 UltraWave,
68 Knock,
69 Greet,
70 Log,
71 Err,
72}
73
74#[derive(
75 Debug,
76 Clone,
77 Serialize,
78 Deserialize,
79 Eq,
80 PartialEq,
81 strum_macros::Display,
82 Autobox,
83 cosmic_macros_primitive::ToSubstance,
84)]
85pub enum Substance {
86 Empty,
87 List(SubstanceList),
88 Map(SubstanceMap),
89 Point(Point),
90 Surface(Surface),
91 Text(String),
92 Stub(Stub),
93 Details(Details),
94 Meta(Meta),
95 Bin(Bin),
96 Boolean(bool),
97 Int(i64),
98 Status(Status),
99 Particle(Particle),
100 Location(ParticleLocation),
101 RawCommand(RawCommand),
102 Command(Box<Command>),
103 FormErrs(FormErrs),
104 Json(Value),
105 MultipartForm(MultipartForm),
106 DirectedCore(Box<DirectedCore>),
107 ReflectedCore(Box<ReflectedCore>),
108 Hyper(HyperSubstance),
109 Token(Token),
110 UltraWave(Box<UltraWave>),
111 Knock(Knock),
112 Greet(Greet),
113 Log(LogSubstance),
114 Err(SpaceErr),
115}
116
117impl Substance {
118 pub fn ultrawave(&self) -> Option<&UltraWave> {
119 if let Substance::UltraWave(wave) = self {
120 Some(wave.as_ref())
121 } else {
122 None
123 }
124 }
125
126 pub fn ultrawave_mut(&mut self) -> Option<&mut UltraWave> {
127 if let Substance::UltraWave(wave) = self {
128 Some(wave.as_mut())
129 } else {
130 None
131 }
132 }
133}
134
135pub trait ToSubstance<S> {
136 fn to_substance(self) -> Result<S, SpaceErr>;
137 fn to_substance_ref(&self) -> Result<&S, SpaceErr>;
138}
139
140pub trait ChildSubstance {}
141
142#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
143pub struct Token {
144 data: String,
145}
146
147impl Token {
148 pub fn new<D: ToString>(data: D) -> Self {
149 Self {
150 data: data.to_string(),
151 }
152 }
153
154 pub fn new_uuid() -> Self {
155 Self::new(util::uuid())
156 }
157}
158
159impl Deref for Token {
160 type Target = String;
161
162 fn deref(&self) -> &Self::Target {
163 &self.data
164 }
165}
166
167impl ToString for Token {
168 fn to_string(&self) -> String {
169 self.data.clone()
170 }
171}
172
173impl FromStr for Token {
174 type Err = SpaceErr;
175
176 fn from_str(s: &str) -> Result<Self, Self::Err> {
177 Ok(Token::new(s))
178 }
179}
180
181impl TryFrom<Pong> for Token {
182 type Error = SpaceErr;
183
184 fn try_from(response: Pong) -> Result<Self, Self::Error> {
185 response.core.body.try_into()
186 }
187}
188
189pub trait ToRequestCore {
190 type Method;
191 fn to_request_core(self) -> DirectedCore;
192}
193
194impl Default for Substance {
195 fn default() -> Self {
196 Substance::Empty
197 }
198}
199
200impl Substance {
201 pub fn to_text(self) -> Result<String, SpaceErr> {
202 if let Substance::Text(text) = self {
203 Ok(text)
204 } else {
205 Err("not a 'Text' payload".into())
206 }
207 }
208
209 pub fn is_some(&self) -> bool {
210 if let Self::Empty = self {
211 false
212 } else {
213 true
214 }
215 }
216
217 pub fn from_bin(bin: Bin) -> Self {
218 Self::Bin(bin)
219 }
220
221 pub fn kind(&self) -> SubstanceKind {
222 match self {
223 Substance::Empty => SubstanceKind::Empty,
224 Substance::List(_) => SubstanceKind::List,
225 Substance::Map(_) => SubstanceKind::Map,
226 Substance::Point(_) => SubstanceKind::Point,
227 Substance::Text(_) => SubstanceKind::Text,
228 Substance::Stub(_) => SubstanceKind::Stub,
229 Substance::Meta(_) => SubstanceKind::Meta,
230 Substance::Bin(_) => SubstanceKind::Bin,
231 Substance::Boolean(_) => SubstanceKind::Boolean,
232 Substance::Int(_) => SubstanceKind::Int,
233 Substance::Status(_) => SubstanceKind::Status,
234 Substance::Particle(_) => SubstanceKind::Particle,
235 Substance::FormErrs(_) => SubstanceKind::FormErrs,
236 Substance::Json(_) => SubstanceKind::Json,
237 Substance::RawCommand(_) => SubstanceKind::RawCommand,
238 Substance::Surface(_) => SubstanceKind::Surface,
239 Substance::Command(_) => SubstanceKind::Command,
240 Substance::DirectedCore(_) => SubstanceKind::DirectedCore,
241 Substance::ReflectedCore(_) => SubstanceKind::ReflectedCore,
242 Substance::Hyper(_) => SubstanceKind::Hyp,
243 Substance::MultipartForm(_) => SubstanceKind::MultipartForm,
244 Substance::Token(_) => SubstanceKind::Token,
245 Substance::UltraWave(_) => SubstanceKind::UltraWave,
246 Substance::Knock(_) => SubstanceKind::Knock,
247 Substance::Greet(_) => SubstanceKind::Greet,
248 Substance::Details(_) => SubstanceKind::Details,
249 Substance::Location(_) => SubstanceKind::Location,
250 Substance::Log(_) => SubstanceKind::Log,
251 Substance::Err(_) => SubstanceKind::Err,
252 }
253 }
254
255 pub fn to_bin(self) -> Result<Bin, SpaceErr> {
256 match self {
257 Substance::Empty => Ok(Arc::new(vec![])),
258 Substance::List(list) => list.to_bin(),
259 Substance::Map(map) => map.to_bin(),
260 Substance::Bin(bin) => Ok(bin),
261 Substance::Text(text) => Ok(Arc::new(text.as_bytes().to_vec())),
262 what => Err(format!("{}.to_bin() not supported", what.kind().to_string()).into()),
263 }
264 }
265}
266
267#[derive(
268 Debug,
269 Clone,
270 Serialize,
271 Deserialize,
272 Eq,
273 PartialEq,
274 Autobox,
275 cosmic_macros_primitive::ToSubstance,
276)]
277pub enum LogSubstance {
278 Log(Log),
279 Span(LogSpan),
280 Event(LogSpanEvent),
281 Audit(AuditLog),
282 Pointless(PointlessLog),
283}
284
285impl TryInto<HashMap<String, Substance>> for Substance {
286 type Error = SpaceErr;
287
288 fn try_into(self) -> Result<HashMap<String, Substance>, Self::Error> {
289 match self {
290 Substance::Map(map) => Ok(map.map),
291 _ => Err("Substance type must a Map".into()),
292 }
293 }
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
297pub struct SubstanceMap {
298 pub map: HashMap<String, Substance>,
299}
300
301impl Deref for SubstanceMap {
302 type Target = HashMap<String, Substance>;
303
304 fn deref(&self) -> &Self::Target {
305 &self.map
306 }
307}
308
309impl DerefMut for SubstanceMap {
310 fn deref_mut(&mut self) -> &mut Self::Target {
311 &mut self.map
312 }
313}
314
315impl Default for SubstanceMap {
316 fn default() -> Self {
317 Self {
318 map: Default::default(),
319 }
320 }
321}
322
323impl SubstanceMap {
324 pub fn to_bin(self) -> Result<Bin, SpaceErr> {
334 Ok(Arc::new(bincode::serialize(&self)?))
335 }
336
337 pub fn new() -> Self {
338 Self {
339 map: HashMap::new(),
340 }
341 }
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
345pub struct FormErrs {
346 map: HashMap<String, String>,
347}
348
349impl FormErrs {
350 pub fn to_cosmic_err(&self) -> SpaceErr {
351 SpaceErr::new(500, self.to_string().as_str())
352 }
353
354 pub fn empty() -> Self {
355 Self {
356 map: HashMap::new(),
357 }
358 }
359
360 pub fn default<S: ToString>(message: S) -> Self {
361 let mut map = HashMap::new();
362 map.insert("default".to_string(), message.to_string());
363 Self { map }
364 }
365}
366
367impl From<SpaceErr> for FormErrs {
368 fn from(err: SpaceErr) -> Self {
369 match err {
370 SpaceErr::Status { status, message } => {
371 Self::default(format!("{} {}", status, message).as_str())
372 }
373 SpaceErr::ParseErrs(_) => Self::default("500: parse error"),
374 }
375 }
376}
377
378impl ToString for FormErrs {
379 fn to_string(&self) -> String {
380 let mut rtn = String::new();
381 for (index, (_, value)) in self.iter().enumerate() {
382 rtn.push_str(value.as_str());
383 if index == self.len() - 1 {
384 rtn.push_str("\n");
385 }
386 }
387 rtn
388 }
389}
390
391impl Deref for FormErrs {
392 type Target = HashMap<String, String>;
393
394 fn deref(&self) -> &Self::Target {
395 &self.map
396 }
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
400pub struct SubstanceList {
401 pub list: Vec<Box<Substance>>,
402}
403
404impl ToString for SubstanceList {
405 fn to_string(&self) -> String {
406 "[]".to_string()
407 }
408}
409
410impl SubstanceList {
411 pub fn new() -> Self {
412 Self { list: vec![] }
413 }
414 pub fn to_bin(self) -> Result<Bin, SpaceErr> {
415 Ok(Arc::new(bincode::serialize(&self)?))
416 }
417}
418
419impl Deref for SubstanceList {
420 type Target = Vec<Box<Substance>>;
421
422 fn deref(&self) -> &Self::Target {
423 &self.list
424 }
425}
426
427impl DerefMut for SubstanceList {
428 fn deref_mut(&mut self) -> &mut Self::Target {
429 &mut self.list
430 }
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
434pub struct ListPattern {
435 pub primitive: SubstanceKind,
436 pub range: NumRange,
437}
438
439impl ListPattern {
440 pub fn is_match(&self, list: &SubstanceList) -> Result<(), SpaceErr> {
441 unimplemented!()
457 }
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
461pub enum NumRange {
462 MinMax { min: usize, max: usize },
463 Exact(usize),
464 Any,
465}
466
467pub type SubstanceTypePatternCtx = SubstanceTypePatternDef<PointCtx>;
468pub type SubstanceTypePatternVar = SubstanceTypePatternDef<PointVar>;
469
470#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
471pub enum SubstanceTypePatternDef<Pnt> {
472 Empty,
473 Primitive(SubstanceKind),
474 List(ListPattern),
475 Map(Box<MapPatternDef<Pnt>>),
476}
477
478impl ToResolved<SubstanceTypePatternDef<Point>> for SubstanceTypePatternDef<PointCtx> {
479 fn to_resolved(self, env: &Env) -> Result<SubstanceTypePatternDef<Point>, SpaceErr> {
480 match self {
481 SubstanceTypePatternDef::Empty => Ok(SubstanceTypePatternDef::Empty),
482 SubstanceTypePatternDef::Primitive(payload_type) => {
483 Ok(SubstanceTypePatternDef::Primitive(payload_type))
484 }
485 SubstanceTypePatternDef::List(list) => Ok(SubstanceTypePatternDef::List(list)),
486 SubstanceTypePatternDef::Map(map) => {
487 Err("MapPatternCtx resolution not supported yet...".into())
488 }
489 }
490 }
491}
492
493impl ToResolved<SubstanceTypePatternCtx> for SubstanceTypePatternVar {
494 fn to_resolved(self, env: &Env) -> Result<SubstanceTypePatternCtx, SpaceErr> {
495 match self {
496 SubstanceTypePatternVar::Empty => Ok(SubstanceTypePatternCtx::Empty),
497 SubstanceTypePatternVar::Primitive(payload_type) => {
498 Ok(SubstanceTypePatternCtx::Primitive(payload_type))
499 }
500 SubstanceTypePatternVar::List(list) => Ok(SubstanceTypePatternCtx::List(list)),
501 SubstanceTypePatternVar::Map(map) => {
502 Err("MapPatternCtx resolution not supported yet...".into())
503 }
504 }
505 }
506}
507
508impl<Pnt> SubstanceTypePatternDef<Pnt> {
509 pub fn is_match(&self, payload: &Substance) -> Result<(), ()> {
510 unimplemented!();
511 }
572}
573
574pub type SubstancePatternVar = SubstancePatternDef<PointVar>;
575pub type SubstancePatternCtx = SubstancePatternDef<PointCtx>;
576pub type SubstancePattern = SubstancePatternDef<Point>;
577
578#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
579pub struct SubstancePatternDef<Pnt> {
580 pub structure: SubstanceTypePatternDef<Pnt>,
581 pub format: Option<SubstanceFormat>,
582 pub validator: Option<CallWithConfigDef<Pnt>>,
583}
584
585impl ToResolved<SubstancePatternCtx> for SubstancePatternVar {
586 fn to_resolved(self, env: &Env) -> Result<SubstancePatternCtx, SpaceErr> {
587 let mut errs = vec![];
588 let structure = match self.structure.to_resolved(env) {
589 Ok(structure) => Some(structure),
590 Err(err) => {
591 errs.push(err);
592 None
593 }
594 };
595 let validator = match self.validator {
596 None => None,
597 Some(validator) => match validator.to_resolved(env) {
598 Ok(validator) => Some(validator),
599 Err(err) => {
600 errs.push(err);
601 None
602 }
603 },
604 };
605
606 if errs.is_empty() {
607 Ok(SubstancePatternCtx {
608 structure: structure.expect("structure"),
609 validator: validator,
610 format: self.format,
611 })
612 } else {
613 Err(ParseErrs::fold(errs).into())
614 }
615 }
616}
617
618impl ToResolved<SubstancePattern> for SubstancePatternCtx {
619 fn to_resolved(self, resolver: &Env) -> Result<SubstancePattern, SpaceErr> {
620 let mut errs = vec![];
621 let structure = match self.structure.to_resolved(resolver) {
622 Ok(structure) => Some(structure),
623 Err(err) => {
624 errs.push(err);
625 None
626 }
627 };
628 let validator = match self.validator {
629 None => None,
630 Some(validator) => match validator.to_resolved(resolver) {
631 Ok(validator) => Some(validator),
632 Err(err) => {
633 errs.push(err);
634 None
635 }
636 },
637 };
638
639 if errs.is_empty() {
640 Ok(SubstancePattern {
641 structure: structure.expect("structure"),
642 validator: validator,
643 format: self.format,
644 })
645 } else {
646 Err(ParseErrs::fold(errs).into())
647 }
648 }
649}
650
651impl<Pnt> ValueMatcher<Substance> for SubstancePatternDef<Pnt> {
652 fn is_match(&self, payload: &Substance) -> Result<(), ()> {
653 self.structure.is_match(&payload)?;
654
655 Ok(())
657 }
658}
659
660#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
661pub struct CallWithConfigDef<Pnt> {
662 pub call: CallDef<Pnt>,
663 pub config: Option<Pnt>,
664}
665
666pub type CallWithConfig = CallWithConfigDef<Point>;
667pub type CallWithConfigCtx = CallWithConfigDef<PointCtx>;
668pub type CallWithConfigVar = CallWithConfigDef<PointVar>;
669
670impl ToResolved<CallWithConfigCtx> for CallWithConfigVar {
671 fn to_resolved(self, resolver: &Env) -> Result<CallWithConfigCtx, SpaceErr> {
672 let mut errs = vec![];
673 let call = match self.call.to_resolved(resolver) {
674 Ok(call) => Some(call),
675 Err(err) => {
676 errs.push(err);
677 None
678 }
679 };
680 let config = match self.config {
681 None => None,
682 Some(config) => match config.to_resolved(resolver) {
683 Ok(config) => Some(config),
684 Err(err) => {
685 errs.push(err);
686 None
687 }
688 },
689 };
690
691 if errs.is_empty() {
692 Ok(CallWithConfigCtx {
693 call: call.expect("call"),
694 config,
695 })
696 } else {
697 Err(ParseErrs::fold(errs).into())
698 }
699 }
700}
701
702impl ToResolved<CallWithConfig> for CallWithConfigCtx {
703 fn to_resolved(self, resolver: &Env) -> Result<CallWithConfig, SpaceErr> {
704 let mut errs = vec![];
705 let call = match self.call.to_resolved(resolver) {
706 Ok(call) => Some(call),
707 Err(err) => {
708 errs.push(err);
709 None
710 }
711 };
712 let config = match self.config {
713 None => None,
714 Some(config) => match config.to_resolved(resolver) {
715 Ok(config) => Some(config),
716 Err(err) => {
717 errs.push(err);
718 None
719 }
720 },
721 };
722
723 if errs.is_empty() {
724 Ok(CallWithConfig {
725 call: call.expect("call"),
726 config,
727 })
728 } else {
729 Err(ParseErrs::fold(errs).into())
730 }
731 }
732}
733
734pub type Call = CallDef<Point>;
735pub type CallCtx = CallDef<PointCtx>;
736pub type CallVar = CallDef<PointVar>;
737
738impl ToResolved<Call> for CallCtx {
739 fn to_resolved(self, env: &Env) -> Result<Call, SpaceErr> {
740 Ok(Call {
741 point: self.point.to_resolved(env)?,
742 kind: self.kind,
743 })
744 }
745}
746
747impl ToResolved<CallCtx> for CallVar {
748 fn to_resolved(self, env: &Env) -> Result<CallCtx, SpaceErr> {
749 Ok(CallCtx {
750 point: self.point.to_resolved(env)?,
751 kind: self.kind,
752 })
753 }
754}
755
756impl ToResolved<Call> for CallVar {
757 fn to_resolved(self, env: &Env) -> Result<Call, SpaceErr> {
758 let call: CallCtx = self.to_resolved(env)?;
759 call.to_resolved(env)
760 }
761}
762
763#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
764pub struct CallDef<Pnt> {
765 pub point: Pnt,
766 pub kind: CallKind,
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
770pub enum CallKind {
771 Cmd(CmdCall),
772 Hyp(HypCall),
773 Ext(ExtCall),
774 Http(HttpCall),
775}
776
777impl CallKind {
778 }
797
798impl ToString for Call {
799 fn to_string(&self) -> String {
800 format!("{}^{}", self.point.to_string(), self.kind.to_string())
801 }
802}
803
804#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
805pub struct ExtCall {
806 pub path: Subst<Tw<String>>,
807 pub method: ExtMethod,
808}
809
810impl ExtCall {
811 pub fn new(method: ExtMethod, path: Subst<Tw<String>>) -> Self {
812 Self { method, path }
813 }
814}
815
816impl ToString for ExtCall {
817 fn to_string(&self) -> String {
818 format!("Ext<{}>{}", self.method.to_string(), self.path.to_string())
819 }
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
823pub struct CmdCall {
824 pub path: Subst<Tw<String>>,
825 pub method: CmdMethod,
826}
827
828impl CmdCall {
829 pub fn new(method: CmdMethod, path: Subst<Tw<String>>) -> Self {
830 Self { method, path }
831 }
832}
833
834impl ToString for CmdCall {
835 fn to_string(&self) -> String {
836 format!("Cmd<{}>{}", self.method.to_string(), self.path.to_string())
837 }
838}
839
840#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
841pub struct HypCall {
842 pub path: Subst<Tw<String>>,
843 pub method: HypMethod,
844}
845
846impl HypCall {
847 pub fn new(method: HypMethod, path: Subst<Tw<String>>) -> Self {
848 Self { method, path }
849 }
850}
851
852impl ToString for HypCall {
853 fn to_string(&self) -> String {
854 format!("Hyp<{}>{}", self.method.to_string(), self.path.to_string())
855 }
856}
857
858#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
859pub struct HttpCall {
860 pub path: Subst<Tw<String>>,
861
862 pub method: HttpMethod,
863}
864
865impl HttpCall {
866 pub fn new(method: HttpMethod, path: Subst<Tw<String>>) -> Self {
867 Self { method, path }
868 }
869}
870
871impl ToString for HttpCall {
872 fn to_string(&self) -> String {
873 format!("Http<{}>{}", self.method.to_string(), self.path.to_string())
874 }
875}
876
877impl ValueMatcher<HttpMethod> for HttpMethod {
878 fn is_match(&self, found: &HttpMethod) -> Result<(), ()> {
879 if *self == *found {
880 Ok(())
881 } else {
882 Err(())
883 }
884 }
885}
886
887impl ToString for CallKind {
888 fn to_string(&self) -> String {
889 match self {
890 CallKind::Ext(msg) => msg.to_string(),
891 CallKind::Http(http) => http.to_string(),
892 CallKind::Cmd(cmd) => cmd.to_string(),
893 CallKind::Hyp(sys) => sys.to_string(),
894 }
895 }
896}
897
898#[derive(
899 Debug,
900 Clone,
901 Eq,
902 PartialEq,
903 strum_macros::Display,
904 strum_macros::EnumString,
905 Serialize,
906 Deserialize,
907)]
908pub enum SubstanceFormat {
909 #[strum(serialize = "json")]
910 Json,
911 #[strum(serialize = "image")]
912 Image,
913}
914
915pub type MapPattern = MapPatternDef<Point>;
916pub type MapPatternCtx = MapPatternDef<PointCtx>;
917pub type MapPatternVar = MapPatternDef<PointVar>;
918
919#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
920pub struct MapPatternDef<Pnt> {
921 pub required: HashMap<String, ValuePattern<SubstancePatternDef<Pnt>>>,
922 pub allowed: ValuePattern<SubstancePatternDef<Pnt>>,
923}
924
925impl<Pnt> Default for MapPatternDef<Pnt> {
926 fn default() -> Self {
927 MapPatternDef {
928 required: Default::default(),
929 allowed: ValuePattern::Any,
930 }
931 }
932}
933
934impl<Pnt> ToString for MapPatternDef<Pnt> {
935 fn to_string(&self) -> String {
936 "Map?".to_string()
937 }
938}
939
940impl<Pnt> MapPatternDef<Pnt> {
941 pub fn new(
942 required: HashMap<String, ValuePattern<SubstancePatternDef<Pnt>>>,
943 allowed: ValuePattern<SubstancePatternDef<Pnt>>,
944 ) -> Self {
945 MapPatternDef { required, allowed }
946 }
947
948 pub fn empty() -> Self {
949 Self {
950 required: HashMap::new(),
951 allowed: ValuePattern::None,
952 }
953 }
954
955 pub fn any() -> Self {
956 Self {
957 required: HashMap::new(),
958 allowed: ValuePattern::Any,
959 }
960 }
961
962 pub fn is_match(&self, map: &SubstanceMap) -> Result<(), ()> {
963 for (key, payload) in &map.map {
965 if !self.required.contains_key(key) {
966 match &self.allowed {
967 ValuePattern::Any => {}
968 ValuePattern::None => {
969 return Err(());
970 }
971 ValuePattern::Pattern(pattern) => {
972 pattern.is_match(payload)?;
973 }
974 }
975 }
976 }
977
978 for (key, constraint) in &self.required {
980 if !map.contains_key(key) {
981 return Err(());
982 }
983 constraint.is_match(
984 &map.get(key)
985 .expect("expected map element after testing for it"),
986 )?;
987 }
988
989 Ok(())
990 }
991}
992
993#[derive(Debug, Clone, Serialize, Deserialize)]
994pub struct SubstanceRef<PAYLOAD_CLAIM, PAYLOAD_PATTERN> {
995 pub claim: PAYLOAD_CLAIM,
996 pub pattern: PAYLOAD_PATTERN,
997}
998
999#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
1000pub struct MultipartForm {
1001 data: String,
1002}
1003
1004impl TryInto<HashMap<String, String>> for MultipartForm {
1005 type Error = SpaceErr;
1006
1007 fn try_into(self) -> Result<HashMap<String, String>, Self::Error> {
1008 let map: HashMap<String, String> = serde_urlencoded::from_str(&self.data)?;
1009 Ok(map)
1010 }
1011}
1012
1013impl ToRequestCore for MultipartForm {
1014 type Method = HttpMethod;
1015
1016 fn to_request_core(self) -> DirectedCore {
1017 let mut headers = HeaderMap::new();
1018
1019 headers.insert(
1020 "Content-Type".to_string(),
1021 "application/x-www-form-urlencoded".to_string(),
1022 );
1023
1024 DirectedCore {
1025 headers,
1026 method: HttpMethod::Post.into(),
1027 uri: Url::parse("/").unwrap(),
1028 body: Substance::MultipartForm(self),
1029 }
1030 }
1031}
1032
1033impl MultipartForm {
1034 pub fn data(&self) -> &str {
1035 self.data.as_str()
1036 }
1037}
1038
1039impl Deref for MultipartForm {
1040 type Target = str;
1041
1042 fn deref(&self) -> &Self::Target {
1043 self.data()
1044 }
1045}
1046
1047impl ToString for MultipartForm {
1048 fn to_string(&self) -> String {
1049 self.data.clone()
1050 }
1051}
1052
1053pub struct MultipartFormBuilder {
1054 map: HashMap<String, String>,
1055}
1056
1057impl MultipartFormBuilder {
1058 pub fn new() -> Self {
1059 Self {
1060 map: HashMap::new(),
1061 }
1062 }
1063
1064 pub fn put<S: ToString>(&mut self, key: S, value: S) {
1065 self.insert(key.to_string(), value.to_string());
1066 }
1067
1068 pub fn get<S: ToString>(&self, key: S) -> Option<&String> {
1069 self.map.get(&key.to_string())
1070 }
1071}
1072
1073impl Deref for MultipartFormBuilder {
1074 type Target = HashMap<String, String>;
1075
1076 fn deref(&self) -> &Self::Target {
1077 &self.map
1078 }
1079}
1080
1081impl DerefMut for MultipartFormBuilder {
1082 fn deref_mut(&mut self) -> &mut Self::Target {
1083 &mut self.map
1084 }
1085}
1086
1087impl MultipartFormBuilder {
1088 pub fn build(self) -> Result<MultipartForm, SpaceErr> {
1089 let data = serde_urlencoded::to_string(&self.map)?;
1090 Ok(MultipartForm { data })
1091 }
1092}
1093
1094pub type Bin = Arc<Vec<u8>>;