1use std::collections::HashSet;
4use std::fmt;
5use std::sync::Arc;
6
7use indexmap::IndexMap;
8use wdl_ast::Diagnostic;
9use wdl_ast::Span;
10
11use crate::document::Input;
12use crate::document::Output;
13
14pub mod v1;
15
16pub fn display_types(slice: &[Type]) -> impl fmt::Display + use<'_> {
18 struct Display<'a>(&'a [Type]);
20
21 impl fmt::Display for Display<'_> {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 for (i, ty) in self.0.iter().enumerate() {
24 if i > 0 {
25 if self.0.len() == 2 {
26 write!(f, " ")?;
27 } else {
28 write!(f, ", ")?;
29 }
30
31 if i == self.0.len() - 1 {
32 write!(f, "or ")?;
33 }
34 }
35
36 write!(f, "type `{ty}`")?;
37 }
38
39 Ok(())
40 }
41 }
42
43 Display(slice)
44}
45
46pub trait TypeNameResolver {
48 fn resolve(&mut self, name: &str, span: Span) -> Result<Type, Diagnostic>;
50}
51
52pub trait Optional {
54 fn is_optional(&self) -> bool;
56
57 fn optional(&self) -> Self;
59
60 fn require(&self) -> Self;
62}
63
64pub trait Coercible {
66 fn is_coercible_to(&self, target: &Self) -> bool;
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72pub enum PrimitiveType {
73 Boolean,
75 Integer,
77 Float,
79 String,
81 File,
83 Directory,
85}
86
87impl Coercible for PrimitiveType {
88 fn is_coercible_to(&self, target: &Self) -> bool {
89 if self == target {
90 return true;
91 }
92
93 match (self, target) {
94 (Self::String, Self::File) |
96 (Self::String, Self::Directory) |
98 (Self::Integer, Self::Float) |
100 (Self::File, Self::String) |
102 (Self::Directory, Self::String)
104 => true,
105
106 _ => false
108 }
109 }
110}
111
112impl fmt::Display for PrimitiveType {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 match self {
115 Self::Boolean => write!(f, "Boolean")?,
116 Self::Integer => write!(f, "Int")?,
117 Self::Float => write!(f, "Float")?,
118 Self::String => write!(f, "String")?,
119 Self::File => write!(f, "File")?,
120 Self::Directory => write!(f, "Directory")?,
121 }
122
123 Ok(())
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum HiddenType {
133 Hints,
135 Input,
137 Output,
139 TaskPreEvaluation,
142 TaskPostEvaluation,
145 PreviousTaskData,
150}
151
152impl fmt::Display for HiddenType {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 match self {
155 Self::Hints => write!(f, "hints"),
156 Self::Input => write!(f, "input"),
157 Self::Output => write!(f, "output"),
158 Self::TaskPreEvaluation | Self::TaskPostEvaluation => write!(f, "task"),
159 Self::PreviousTaskData => write!(f, "task.previous"),
160 }
161 }
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
166pub enum Type {
167 Primitive(PrimitiveType, bool),
171 Compound(CompoundType, bool),
175 Object,
177 OptionalObject,
179 Union,
185 None,
187 Hidden(HiddenType),
192 Call(CallType),
194}
195
196impl Type {
197 pub fn as_primitive(&self) -> Option<PrimitiveType> {
201 match self {
202 Self::Primitive(ty, _) => Some(*ty),
203 _ => None,
204 }
205 }
206
207 pub fn as_compound(&self) -> Option<&CompoundType> {
211 match self {
212 Self::Compound(ty, _) => Some(ty),
213 _ => None,
214 }
215 }
216
217 pub fn as_array(&self) -> Option<&ArrayType> {
221 match self {
222 Self::Compound(CompoundType::Array(ty), _) => Some(ty),
223 _ => None,
224 }
225 }
226
227 pub fn as_pair(&self) -> Option<&PairType> {
231 match self {
232 Self::Compound(CompoundType::Pair(ty), _) => Some(ty),
233 _ => None,
234 }
235 }
236
237 pub fn as_map(&self) -> Option<&MapType> {
241 match self {
242 Self::Compound(CompoundType::Map(ty), _) => Some(ty),
243 _ => None,
244 }
245 }
246
247 pub fn as_struct(&self) -> Option<&StructType> {
251 match self {
252 Self::Compound(CompoundType::Struct(ty), _) => Some(ty),
253 _ => None,
254 }
255 }
256
257 pub fn as_call(&self) -> Option<&CallType> {
261 match self {
262 Self::Call(ty) => Some(ty),
263 _ => None,
264 }
265 }
266
267 pub fn is_union(&self) -> bool {
269 matches!(self, Type::Union)
270 }
271
272 pub fn is_none(&self) -> bool {
274 matches!(self, Type::None)
275 }
276
277 pub fn promote_scatter(&self) -> Self {
282 if let Self::Call(ty) = self {
284 return Self::Call(ty.promote_scatter());
285 }
286
287 Type::Compound(ArrayType::new(self.clone()).into(), false)
288 }
289
290 pub fn common_type(&self, other: &Type) -> Option<Type> {
294 if other.is_union() {
296 return Some(self.clone());
297 }
298
299 if self.is_union() {
301 return Some(other.clone());
302 }
303
304 if other.is_none() {
307 return Some(self.optional());
308 }
309
310 if self.is_none() {
312 return Some(other.optional());
313 }
314
315 if other.is_coercible_to(self) {
317 return Some(self.clone());
318 }
319
320 if self.is_coercible_to(other) {
322 return Some(other.clone());
323 }
324
325 if let (Some(this), Some(other)) = (self.as_compound(), other.as_compound())
327 && let Some(ty) = this.common_type(other)
328 {
329 return Some(Self::Compound(ty, self.is_optional()));
330 }
331
332 if let (Some(this), Some(other)) = (self.as_call(), self.as_call())
334 && this == other
335 {
336 return Some(Self::Call(this.clone()));
337 }
338
339 None
340 }
341}
342
343impl fmt::Display for Type {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 match self {
346 Self::Primitive(ty, optional) => {
347 ty.fmt(f)?;
348 if *optional { write!(f, "?") } else { Ok(()) }
349 }
350 Self::Compound(ty, optional) => {
351 ty.fmt(f)?;
352 if *optional { write!(f, "?") } else { Ok(()) }
353 }
354 Self::Object => {
355 write!(f, "Object")
356 }
357 Self::OptionalObject => {
358 write!(f, "Object?")
359 }
360 Self::Union => write!(f, "Union"),
361 Self::None => write!(f, "None"),
362 Self::Hidden(ty) => ty.fmt(f),
363 Self::Call(ty) => ty.fmt(f),
364 }
365 }
366}
367
368impl Optional for Type {
369 fn is_optional(&self) -> bool {
370 match self {
371 Self::Primitive(_, optional) => *optional,
372 Self::Compound(_, optional) => *optional,
373 Self::OptionalObject | Self::None => true,
374 Self::Object | Self::Union | Self::Hidden(_) | Self::Call(_) => false,
375 }
376 }
377
378 fn optional(&self) -> Self {
379 match self {
380 Self::Primitive(ty, _) => Self::Primitive(*ty, true),
381 Self::Compound(ty, _) => Self::Compound(ty.clone(), true),
382 Self::Object => Self::OptionalObject,
383 Self::Union => Self::None,
384 Self::Call(ty) => Self::Call(ty.optional()),
385 ty => ty.clone(),
386 }
387 }
388
389 fn require(&self) -> Self {
390 match self {
391 Self::Primitive(ty, _) => Self::Primitive(*ty, false),
392 Self::Compound(ty, _) => Self::Compound(ty.clone(), false),
393 Self::OptionalObject => Self::Object,
394 Self::None => Self::Union,
395 ty => ty.clone(),
396 }
397 }
398}
399
400impl Coercible for Type {
401 fn is_coercible_to(&self, target: &Self) -> bool {
402 if self.eq(target) {
403 return true;
404 }
405
406 match (self, target) {
407 (Self::Primitive(src, src_opt), Self::Primitive(target, target_opt)) => {
408 if *src_opt && !*target_opt {
410 return false;
411 }
412
413 src.is_coercible_to(target)
414 }
415 (Self::Compound(src, src_opt), Self::Compound(target, target_opt)) => {
416 if *src_opt && !*target_opt {
418 return false;
419 }
420
421 src.is_coercible_to(target)
422 }
423
424 (Self::Object, Self::Object)
426 | (Self::Object, Self::OptionalObject)
427 | (Self::OptionalObject, Self::OptionalObject) => true,
428
429 (Self::Compound(src, false), Self::Object)
433 | (Self::Compound(src, false), Self::OptionalObject)
434 | (Self::Compound(src, _), Self::OptionalObject) => match src {
435 CompoundType::Map(src) => {
436 src.key_type.is_coercible_to(&PrimitiveType::String.into())
437 }
438 CompoundType::Struct(_) => true,
439 _ => false,
440 },
441
442 (Self::Object, Self::Compound(target, _))
448 | (Self::OptionalObject, Self::Compound(target, true)) => {
449 match target {
450 CompoundType::Map(target) => {
451 Type::from(PrimitiveType::String).is_coercible_to(&target.key_type)
452 }
453 CompoundType::Struct(_) => {
454 true
456 }
457 _ => false,
458 }
459 }
460
461 (Self::Union, _) | (_, Self::Union) => true,
463
464 (Self::None, ty) if ty.is_optional() => true,
466
467 _ => false,
469 }
470 }
471}
472
473impl From<PrimitiveType> for Type {
474 fn from(value: PrimitiveType) -> Self {
475 Self::Primitive(value, false)
476 }
477}
478
479impl From<CompoundType> for Type {
480 fn from(value: CompoundType) -> Self {
481 Self::Compound(value, false)
482 }
483}
484
485impl From<ArrayType> for Type {
486 fn from(value: ArrayType) -> Self {
487 Self::Compound(value.into(), false)
488 }
489}
490
491impl From<PairType> for Type {
492 fn from(value: PairType) -> Self {
493 Self::Compound(value.into(), false)
494 }
495}
496
497impl From<MapType> for Type {
498 fn from(value: MapType) -> Self {
499 Self::Compound(value.into(), false)
500 }
501}
502
503impl From<StructType> for Type {
504 fn from(value: StructType) -> Self {
505 Self::Compound(value.into(), false)
506 }
507}
508
509impl From<CallType> for Type {
510 fn from(value: CallType) -> Self {
511 Self::Call(value)
512 }
513}
514
515#[derive(Debug, Clone, PartialEq, Eq)]
517pub enum CompoundType {
518 Array(ArrayType),
520 Pair(Arc<PairType>),
522 Map(Arc<MapType>),
524 Struct(Arc<StructType>),
526}
527
528impl CompoundType {
529 pub fn as_array(&self) -> Option<&ArrayType> {
533 match self {
534 Self::Array(ty) => Some(ty),
535 _ => None,
536 }
537 }
538
539 pub fn as_pair(&self) -> Option<&PairType> {
543 match self {
544 Self::Pair(ty) => Some(ty),
545 _ => None,
546 }
547 }
548
549 pub fn as_map(&self) -> Option<&MapType> {
553 match self {
554 Self::Map(ty) => Some(ty),
555 _ => None,
556 }
557 }
558
559 pub fn as_struct(&self) -> Option<&StructType> {
563 match self {
564 Self::Struct(ty) => Some(ty),
565 _ => None,
566 }
567 }
568
569 fn common_type(&self, other: &Self) -> Option<CompoundType> {
574 match (self, other) {
577 (Self::Array(this), Self::Array(other)) => {
578 let element_type = this.element_type.common_type(&other.element_type)?;
579 Some(ArrayType::new(element_type).into())
580 }
581 (Self::Pair(this), Self::Pair(other)) => {
582 let left_type = this.left_type.common_type(&other.left_type)?;
583 let right_type = this.right_type.common_type(&other.right_type)?;
584 Some(PairType::new(left_type, right_type).into())
585 }
586 (Self::Map(this), Self::Map(other)) => {
587 let key_type = this.key_type.common_type(&other.key_type)?;
588 let value_type = this.value_type.common_type(&other.value_type)?;
589 Some(MapType::new(key_type, value_type).into())
590 }
591 _ => None,
592 }
593 }
594}
595
596impl fmt::Display for CompoundType {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 match self {
599 Self::Array(ty) => ty.fmt(f),
600 Self::Pair(ty) => ty.fmt(f),
601 Self::Map(ty) => ty.fmt(f),
602 Self::Struct(ty) => ty.fmt(f),
603 }
604 }
605}
606
607impl Coercible for CompoundType {
608 fn is_coercible_to(&self, target: &Self) -> bool {
609 match (self, target) {
610 (Self::Array(src), Self::Array(target)) => src.is_coercible_to(target),
613
614 (Self::Pair(src), Self::Pair(target)) => src.is_coercible_to(target),
617
618 (Self::Map(src), Self::Map(target)) => src.is_coercible_to(target),
621
622 (Self::Struct(src), Self::Struct(target)) => src.is_coercible_to(target),
625
626 (Self::Map(src), Self::Struct(target)) => {
629 if !src.key_type.is_coercible_to(&PrimitiveType::String.into()) {
630 return false;
631 }
632
633 if !target
635 .members
636 .values()
637 .all(|ty| src.value_type.is_coercible_to(ty))
638 {
639 return false;
640 }
641
642 true
644 }
645
646 (Self::Struct(src), Self::Map(target)) => {
649 if !Type::from(PrimitiveType::String).is_coercible_to(&target.key_type) {
650 return false;
651 }
652
653 if !src
655 .members
656 .values()
657 .all(|ty| ty.is_coercible_to(&target.value_type))
658 {
659 return false;
660 }
661
662 true
663 }
664
665 _ => false,
666 }
667 }
668}
669
670impl From<ArrayType> for CompoundType {
671 fn from(value: ArrayType) -> Self {
672 Self::Array(value)
673 }
674}
675
676impl From<PairType> for CompoundType {
677 fn from(value: PairType) -> Self {
678 Self::Pair(value.into())
679 }
680}
681
682impl From<MapType> for CompoundType {
683 fn from(value: MapType) -> Self {
684 Self::Map(value.into())
685 }
686}
687
688impl From<StructType> for CompoundType {
689 fn from(value: StructType) -> Self {
690 Self::Struct(value.into())
691 }
692}
693
694#[derive(Debug, Clone, PartialEq, Eq)]
696pub struct ArrayType {
697 element_type: Arc<Type>,
699 non_empty: bool,
701}
702
703impl ArrayType {
704 pub fn new(element_type: impl Into<Type>) -> Self {
706 Self {
707 element_type: Arc::new(element_type.into()),
708 non_empty: false,
709 }
710 }
711
712 pub fn non_empty(element_type: impl Into<Type>) -> Self {
714 Self {
715 element_type: Arc::new(element_type.into()),
716 non_empty: true,
717 }
718 }
719
720 pub fn element_type(&self) -> &Type {
722 &self.element_type
723 }
724
725 pub fn is_non_empty(&self) -> bool {
727 self.non_empty
728 }
729
730 pub fn unqualified(self) -> ArrayType {
732 Self {
733 element_type: self.element_type,
734 non_empty: false,
735 }
736 }
737}
738
739impl fmt::Display for ArrayType {
740 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741 write!(f, "Array[{ty}]", ty = self.element_type)?;
742
743 if self.non_empty {
744 write!(f, "+")?;
745 }
746
747 Ok(())
748 }
749}
750
751impl Coercible for ArrayType {
752 fn is_coercible_to(&self, target: &Self) -> bool {
753 self.element_type.is_coercible_to(&target.element_type)
755 }
756}
757
758#[derive(Debug, Clone, PartialEq, Eq)]
760pub struct PairType {
761 left_type: Type,
763 right_type: Type,
765}
766
767impl PairType {
768 pub fn new(left_type: impl Into<Type>, right_type: impl Into<Type>) -> Self {
770 Self {
771 left_type: left_type.into(),
772 right_type: right_type.into(),
773 }
774 }
775
776 pub fn left_type(&self) -> &Type {
778 &self.left_type
779 }
780
781 pub fn right_type(&self) -> &Type {
783 &self.right_type
784 }
785}
786
787impl fmt::Display for PairType {
788 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
789 write!(
790 f,
791 "Pair[{left}, {right}]",
792 left = self.left_type,
793 right = self.right_type
794 )?;
795
796 Ok(())
797 }
798}
799
800impl Coercible for PairType {
801 fn is_coercible_to(&self, target: &Self) -> bool {
802 self.left_type.is_coercible_to(&target.left_type)
803 && self.right_type.is_coercible_to(&target.right_type)
804 }
805}
806
807#[derive(Debug, Clone, PartialEq, Eq)]
809pub struct MapType {
810 key_type: Type,
812 value_type: Type,
814}
815
816impl MapType {
817 pub fn new(key_type: impl Into<Type>, value_type: impl Into<Type>) -> Self {
819 Self {
820 key_type: key_type.into(),
821 value_type: value_type.into(),
822 }
823 }
824
825 pub fn key_type(&self) -> &Type {
827 &self.key_type
828 }
829
830 pub fn value_type(&self) -> &Type {
832 &self.value_type
833 }
834}
835
836impl fmt::Display for MapType {
837 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
838 write!(
839 f,
840 "Map[{key}, {value}]",
841 key = self.key_type,
842 value = self.value_type
843 )?;
844
845 Ok(())
846 }
847}
848
849impl Coercible for MapType {
850 fn is_coercible_to(&self, target: &Self) -> bool {
851 self.key_type.is_coercible_to(&target.key_type)
852 && self.value_type.is_coercible_to(&target.value_type)
853 }
854}
855
856#[derive(Debug, Clone, PartialEq, Eq)]
858pub struct StructType {
859 name: Arc<String>,
861 members: IndexMap<String, Type>,
863}
864
865impl StructType {
866 pub fn new<N, T>(name: impl Into<String>, members: impl IntoIterator<Item = (N, T)>) -> Self
868 where
869 N: Into<String>,
870 T: Into<Type>,
871 {
872 Self {
873 name: Arc::new(name.into()),
874 members: members
875 .into_iter()
876 .map(|(n, ty)| (n.into(), ty.into()))
877 .collect(),
878 }
879 }
880
881 pub fn name(&self) -> &Arc<String> {
883 &self.name
884 }
885
886 pub fn members(&self) -> &IndexMap<String, Type> {
888 &self.members
889 }
890}
891
892impl fmt::Display for StructType {
893 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
894 write!(f, "{name}", name = self.name)
895 }
896}
897
898impl Coercible for StructType {
899 fn is_coercible_to(&self, target: &Self) -> bool {
900 if self.members.len() != target.members.len() {
901 return false;
902 }
903
904 self.members.iter().all(|(k, v)| {
905 target
906 .members
907 .get(k)
908 .map(|target| v.is_coercible_to(target))
909 .unwrap_or(false)
910 })
911 }
912}
913
914#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
916pub enum CallKind {
917 Task,
919 Workflow,
921}
922
923impl fmt::Display for CallKind {
924 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
925 match self {
926 Self::Task => write!(f, "task"),
927 Self::Workflow => write!(f, "workflow"),
928 }
929 }
930}
931
932#[derive(Debug, Clone, Eq)]
934pub struct CallType {
935 kind: CallKind,
937 namespace: Option<Arc<String>>,
939 name: Arc<String>,
941 specified: Arc<HashSet<String>>,
943 inputs: Arc<IndexMap<String, Input>>,
945 outputs: Arc<IndexMap<String, Output>>,
947}
948
949impl CallType {
950 pub fn new(
952 kind: CallKind,
953 name: impl Into<String>,
954 specified: Arc<HashSet<String>>,
955 inputs: Arc<IndexMap<String, Input>>,
956 outputs: Arc<IndexMap<String, Output>>,
957 ) -> Self {
958 Self {
959 kind,
960 namespace: None,
961 name: Arc::new(name.into()),
962 specified,
963 inputs,
964 outputs,
965 }
966 }
967
968 pub fn namespaced(
971 kind: CallKind,
972 namespace: impl Into<String>,
973 name: impl Into<String>,
974 specified: Arc<HashSet<String>>,
975 inputs: Arc<IndexMap<String, Input>>,
976 outputs: Arc<IndexMap<String, Output>>,
977 ) -> Self {
978 Self {
979 kind,
980 namespace: Some(Arc::new(namespace.into())),
981 name: Arc::new(name.into()),
982 specified,
983 inputs,
984 outputs,
985 }
986 }
987
988 pub fn kind(&self) -> CallKind {
990 self.kind
991 }
992
993 pub fn namespace(&self) -> Option<&str> {
997 self.namespace.as_ref().map(|ns| ns.as_str())
998 }
999
1000 pub fn name(&self) -> &str {
1002 &self.name
1003 }
1004
1005 pub fn specified(&self) -> &HashSet<String> {
1007 &self.specified
1008 }
1009
1010 pub fn inputs(&self) -> &IndexMap<String, Input> {
1012 &self.inputs
1013 }
1014
1015 pub fn outputs(&self) -> &IndexMap<String, Output> {
1017 &self.outputs
1018 }
1019
1020 pub fn optional(&self) -> Self {
1022 let mut ty = self.clone();
1023 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
1024 *output = Output::new(output.ty().optional(), output.name_span());
1025 }
1026
1027 ty
1028 }
1029
1030 pub fn promote_scatter(&self) -> Self {
1032 let mut ty = self.clone();
1033 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
1034 *output = Output::new(output.ty().promote_scatter(), output.name_span());
1035 }
1036
1037 ty
1038 }
1039}
1040
1041impl Coercible for CallType {
1042 fn is_coercible_to(&self, _: &Self) -> bool {
1043 false
1045 }
1046}
1047
1048impl fmt::Display for CallType {
1049 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1050 if let Some(ns) = &self.namespace {
1051 write!(
1052 f,
1053 "call to {kind} `{ns}.{name}`",
1054 kind = self.kind,
1055 name = self.name,
1056 )
1057 } else {
1058 write!(
1059 f,
1060 "call to {kind} `{name}`",
1061 kind = self.kind,
1062 name = self.name,
1063 )
1064 }
1065 }
1066}
1067
1068impl PartialEq for CallType {
1069 fn eq(&self, other: &Self) -> bool {
1070 std::ptr::eq(self, other)
1072 }
1073}
1074
1075#[cfg(test)]
1076mod test {
1077 use pretty_assertions::assert_eq;
1078
1079 use super::*;
1080
1081 #[test]
1082 fn primitive_type_display() {
1083 assert_eq!(PrimitiveType::Boolean.to_string(), "Boolean");
1084 assert_eq!(PrimitiveType::Integer.to_string(), "Int");
1085 assert_eq!(PrimitiveType::Float.to_string(), "Float");
1086 assert_eq!(PrimitiveType::String.to_string(), "String");
1087 assert_eq!(PrimitiveType::File.to_string(), "File");
1088 assert_eq!(PrimitiveType::Directory.to_string(), "Directory");
1089 assert_eq!(
1090 Type::from(PrimitiveType::Boolean).optional().to_string(),
1091 "Boolean?"
1092 );
1093 assert_eq!(
1094 Type::from(PrimitiveType::Integer).optional().to_string(),
1095 "Int?"
1096 );
1097 assert_eq!(
1098 Type::from(PrimitiveType::Float).optional().to_string(),
1099 "Float?"
1100 );
1101 assert_eq!(
1102 Type::from(PrimitiveType::String).optional().to_string(),
1103 "String?"
1104 );
1105 assert_eq!(
1106 Type::from(PrimitiveType::File).optional().to_string(),
1107 "File?"
1108 );
1109 assert_eq!(
1110 Type::from(PrimitiveType::Directory).optional().to_string(),
1111 "Directory?"
1112 );
1113 }
1114
1115 #[test]
1116 fn array_type_display() {
1117 assert_eq!(
1118 ArrayType::new(PrimitiveType::String).to_string(),
1119 "Array[String]"
1120 );
1121 assert_eq!(
1122 ArrayType::non_empty(PrimitiveType::String).to_string(),
1123 "Array[String]+"
1124 );
1125
1126 let ty: Type = ArrayType::new(ArrayType::new(PrimitiveType::String)).into();
1127 assert_eq!(ty.to_string(), "Array[Array[String]]");
1128
1129 let ty = Type::from(ArrayType::non_empty(
1130 Type::from(ArrayType::non_empty(
1131 Type::from(PrimitiveType::String).optional(),
1132 ))
1133 .optional(),
1134 ))
1135 .optional();
1136 assert_eq!(ty.to_string(), "Array[Array[String?]+?]+?");
1137 }
1138
1139 #[test]
1140 fn pair_type_display() {
1141 assert_eq!(
1142 PairType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1143 "Pair[String, Boolean]"
1144 );
1145
1146 let ty: Type = PairType::new(
1147 ArrayType::new(PrimitiveType::String),
1148 ArrayType::new(PrimitiveType::String),
1149 )
1150 .into();
1151 assert_eq!(ty.to_string(), "Pair[Array[String], Array[String]]");
1152
1153 let ty = Type::from(PairType::new(
1154 Type::from(ArrayType::non_empty(
1155 Type::from(PrimitiveType::File).optional(),
1156 ))
1157 .optional(),
1158 Type::from(ArrayType::non_empty(
1159 Type::from(PrimitiveType::File).optional(),
1160 ))
1161 .optional(),
1162 ))
1163 .optional();
1164 assert_eq!(ty.to_string(), "Pair[Array[File?]+?, Array[File?]+?]?");
1165 }
1166
1167 #[test]
1168 fn map_type_display() {
1169 assert_eq!(
1170 MapType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1171 "Map[String, Boolean]"
1172 );
1173
1174 let ty: Type = MapType::new(
1175 PrimitiveType::Boolean,
1176 ArrayType::new(PrimitiveType::String),
1177 )
1178 .into();
1179 assert_eq!(ty.to_string(), "Map[Boolean, Array[String]]");
1180
1181 let ty: Type = Type::from(MapType::new(
1182 PrimitiveType::String,
1183 Type::from(ArrayType::non_empty(
1184 Type::from(PrimitiveType::File).optional(),
1185 ))
1186 .optional(),
1187 ))
1188 .optional();
1189 assert_eq!(ty.to_string(), "Map[String, Array[File?]+?]?");
1190 }
1191
1192 #[test]
1193 fn struct_type_display() {
1194 assert_eq!(
1195 StructType::new("Foobar", std::iter::empty::<(String, Type)>()).to_string(),
1196 "Foobar"
1197 );
1198 }
1199
1200 #[test]
1201 fn object_type_display() {
1202 assert_eq!(Type::Object.to_string(), "Object");
1203 assert_eq!(Type::OptionalObject.to_string(), "Object?");
1204 }
1205
1206 #[test]
1207 fn union_type_display() {
1208 assert_eq!(Type::Union.to_string(), "Union");
1209 }
1210
1211 #[test]
1212 fn none_type_display() {
1213 assert_eq!(Type::None.to_string(), "None");
1214 }
1215
1216 #[test]
1217 fn primitive_type_coercion() {
1218 for ty in [
1221 Type::from(PrimitiveType::Boolean),
1222 PrimitiveType::Directory.into(),
1223 PrimitiveType::File.into(),
1224 PrimitiveType::Float.into(),
1225 PrimitiveType::Integer.into(),
1226 PrimitiveType::String.into(),
1227 ] {
1228 assert!(ty.is_coercible_to(&ty));
1229 assert!(ty.optional().is_coercible_to(&ty.optional()));
1230 assert!(ty.is_coercible_to(&ty.optional()));
1231 assert!(!ty.optional().is_coercible_to(&ty));
1232 }
1233
1234 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::File));
1236 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::Directory));
1237 assert!(PrimitiveType::Integer.is_coercible_to(&PrimitiveType::Float));
1238 assert!(PrimitiveType::File.is_coercible_to(&PrimitiveType::String));
1239 assert!(PrimitiveType::Directory.is_coercible_to(&PrimitiveType::String));
1240 assert!(!PrimitiveType::Float.is_coercible_to(&PrimitiveType::Integer));
1241 }
1242
1243 #[test]
1244 fn object_type_coercion() {
1245 assert!(Type::Object.is_coercible_to(&Type::Object));
1246 assert!(Type::Object.is_coercible_to(&Type::OptionalObject));
1247 assert!(Type::OptionalObject.is_coercible_to(&Type::OptionalObject));
1248 assert!(!Type::OptionalObject.is_coercible_to(&Type::Object));
1249
1250 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1252 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1253
1254 let ty = MapType::new(PrimitiveType::File, PrimitiveType::String).into();
1256 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1257
1258 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1260 assert!(!Type::Object.is_coercible_to(&ty));
1261
1262 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1264 assert!(Type::Object.is_coercible_to(&ty));
1265
1266 let ty = Type::from(MapType::new(PrimitiveType::File, PrimitiveType::String)).optional();
1268 assert!(Type::Object.is_coercible_to(&ty));
1269
1270 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1272 assert!(Type::OptionalObject.is_coercible_to(&ty));
1273
1274 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1276 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1277
1278 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1280 assert!(Type::Object.is_coercible_to(&ty));
1281
1282 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1284 assert!(Type::Object.is_coercible_to(&ty));
1285
1286 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1288 assert!(Type::OptionalObject.is_coercible_to(&ty));
1289
1290 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1292 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1293 }
1294
1295 #[test]
1296 fn array_type_coercion() {
1297 assert!(
1299 ArrayType::new(PrimitiveType::String)
1300 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1301 );
1302 assert!(
1303 ArrayType::new(PrimitiveType::File)
1304 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1305 );
1306 assert!(
1307 ArrayType::new(PrimitiveType::String)
1308 .is_coercible_to(&ArrayType::new(PrimitiveType::File))
1309 );
1310
1311 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1313 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1314 assert!(type1.is_coercible_to(&type2));
1315 assert!(!type2.is_coercible_to(&type1));
1316
1317 let type1: Type = ArrayType::new(type1).into();
1319 let type2 = ArrayType::new(type2).into();
1320 assert!(type1.is_coercible_to(&type2));
1321 assert!(!type2.is_coercible_to(&type1));
1322
1323 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1325 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1326 assert!(type1.is_coercible_to(&type2));
1327 assert!(!type2.is_coercible_to(&type1));
1328
1329 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1331 let type2 = ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
1332 assert!(type1.is_coercible_to(&type2));
1333 assert!(!type2.is_coercible_to(&type1));
1334
1335 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1337 let type2 = ArrayType::new(PrimitiveType::String).into();
1338 assert!(type1.is_coercible_to(&type2));
1339 assert!(type2.is_coercible_to(&type1));
1340
1341 let type1 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1343 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1344 assert!(type1.is_coercible_to(&type2));
1345 assert!(type2.is_coercible_to(&type1));
1346
1347 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1349 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1350 assert!(type1.is_coercible_to(&type2));
1351 assert!(!type2.is_coercible_to(&type1));
1352 }
1353
1354 #[test]
1355 fn pair_type_coercion() {
1356 assert!(
1358 PairType::new(PrimitiveType::String, PrimitiveType::String)
1359 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1360 );
1361 assert!(
1362 PairType::new(PrimitiveType::String, PrimitiveType::String).is_coercible_to(
1363 &PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1364 )
1365 );
1366 assert!(
1367 PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1368 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1369 );
1370
1371 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1373 let type2 = PairType::new(
1374 Type::from(PrimitiveType::File).optional(),
1375 Type::from(PrimitiveType::Directory).optional(),
1376 )
1377 .into();
1378 assert!(type1.is_coercible_to(&type2));
1379 assert!(!type2.is_coercible_to(&type1));
1380
1381 let type1: Type = PairType::new(type1.clone(), type1).into();
1383 let type2 = PairType::new(type2.clone(), type2).into();
1384 assert!(type1.is_coercible_to(&type2));
1385 assert!(!type2.is_coercible_to(&type1));
1386
1387 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1389 let type2 = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1390 assert!(type1.is_coercible_to(&type2));
1391 assert!(type2.is_coercible_to(&type1));
1392
1393 let type1 =
1395 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1396 let type2 =
1397 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1398 assert!(type1.is_coercible_to(&type2));
1399 assert!(type2.is_coercible_to(&type1));
1400
1401 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1403 let type2 =
1404 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1405 assert!(type1.is_coercible_to(&type2));
1406 assert!(!type2.is_coercible_to(&type1));
1407 }
1408
1409 #[test]
1410 fn map_type_coercion() {
1411 assert!(
1413 MapType::new(PrimitiveType::String, PrimitiveType::String)
1414 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1415 );
1416 assert!(
1417 MapType::new(PrimitiveType::String, PrimitiveType::String)
1418 .is_coercible_to(&MapType::new(PrimitiveType::File, PrimitiveType::Directory))
1419 );
1420 assert!(
1421 MapType::new(PrimitiveType::File, PrimitiveType::Directory)
1422 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1423 );
1424
1425 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1427 let type2 = MapType::new(
1428 Type::from(PrimitiveType::File).optional(),
1429 Type::from(PrimitiveType::Directory).optional(),
1430 )
1431 .into();
1432 assert!(type1.is_coercible_to(&type2));
1433 assert!(!type2.is_coercible_to(&type1));
1434
1435 let type1: Type = MapType::new(PrimitiveType::String, type1).into();
1437 let type2 = MapType::new(PrimitiveType::Directory, type2).into();
1438 assert!(type1.is_coercible_to(&type2));
1439 assert!(!type2.is_coercible_to(&type1));
1440
1441 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1443 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1444 assert!(type1.is_coercible_to(&type2));
1445 assert!(type2.is_coercible_to(&type1));
1446
1447 let type1: Type =
1449 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1450 let type2: Type =
1451 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1452 assert!(type1.is_coercible_to(&type2));
1453 assert!(type2.is_coercible_to(&type1));
1454
1455 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1457 let type2 =
1458 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1459 assert!(type1.is_coercible_to(&type2));
1460 assert!(!type2.is_coercible_to(&type1));
1461
1462 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1464 let type2 = StructType::new(
1465 "Foo",
1466 [
1467 ("foo", PrimitiveType::Integer),
1468 ("bar", PrimitiveType::Integer),
1469 ("baz", PrimitiveType::Integer),
1470 ],
1471 )
1472 .into();
1473 assert!(type1.is_coercible_to(&type2));
1474
1475 let type1: Type = MapType::new(PrimitiveType::File, PrimitiveType::Integer).into();
1477 let type2 = StructType::new(
1478 "Foo",
1479 [
1480 ("foo", PrimitiveType::Integer),
1481 ("bar", PrimitiveType::Integer),
1482 ("baz", PrimitiveType::Integer),
1483 ],
1484 )
1485 .into();
1486 assert!(type1.is_coercible_to(&type2));
1487
1488 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1490 let type2 = StructType::new(
1491 "Foo",
1492 [
1493 ("foo", PrimitiveType::Integer),
1494 ("bar", PrimitiveType::String),
1495 ("baz", PrimitiveType::Integer),
1496 ],
1497 )
1498 .into();
1499 assert!(!type1.is_coercible_to(&type2));
1500
1501 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1503 let type2 = StructType::new(
1504 "Foo",
1505 [
1506 ("foo", PrimitiveType::Integer),
1507 ("bar", PrimitiveType::Integer),
1508 ("baz", PrimitiveType::Integer),
1509 ],
1510 )
1511 .into();
1512 assert!(!type1.is_coercible_to(&type2));
1513
1514 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1516 assert!(type1.is_coercible_to(&Type::Object));
1517
1518 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1520 assert!(type1.is_coercible_to(&Type::OptionalObject));
1521
1522 let type1: Type =
1524 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1525 assert!(type1.is_coercible_to(&Type::OptionalObject));
1526
1527 let type1: Type = MapType::new(PrimitiveType::File, PrimitiveType::Integer).into();
1529 assert!(type1.is_coercible_to(&Type::Object));
1530
1531 let type1: Type = MapType::new(PrimitiveType::File, PrimitiveType::Integer).into();
1533 assert!(type1.is_coercible_to(&Type::OptionalObject));
1534
1535 let type1: Type =
1537 Type::from(MapType::new(PrimitiveType::File, PrimitiveType::Integer)).optional();
1538 assert!(type1.is_coercible_to(&Type::OptionalObject));
1539
1540 let type1: Type =
1542 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1543 assert!(!type1.is_coercible_to(&Type::Object));
1544
1545 let type1: Type =
1547 Type::from(MapType::new(PrimitiveType::File, PrimitiveType::Integer)).optional();
1548 assert!(!type1.is_coercible_to(&Type::Object));
1549
1550 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1552 assert!(!type1.is_coercible_to(&Type::Object));
1553 }
1554
1555 #[test]
1556 fn struct_type_coercion() {
1557 let type1: Type = StructType::new(
1559 "Foo",
1560 [
1561 ("foo", PrimitiveType::String),
1562 ("bar", PrimitiveType::String),
1563 ("baz", PrimitiveType::Integer),
1564 ],
1565 )
1566 .into();
1567 let type2 = StructType::new(
1568 "Foo",
1569 [
1570 ("foo", PrimitiveType::String),
1571 ("bar", PrimitiveType::String),
1572 ("baz", PrimitiveType::Integer),
1573 ],
1574 )
1575 .into();
1576 assert!(type1.is_coercible_to(&type2));
1577 assert!(type2.is_coercible_to(&type1));
1578
1579 let type1: Type = StructType::new(
1581 "Foo",
1582 [
1583 ("foo", PrimitiveType::String),
1584 ("bar", PrimitiveType::String),
1585 ("baz", PrimitiveType::Integer),
1586 ],
1587 )
1588 .into();
1589 let type2 = Type::from(StructType::new(
1590 "Foo",
1591 [
1592 ("foo", PrimitiveType::String),
1593 ("bar", PrimitiveType::String),
1594 ("baz", PrimitiveType::Integer),
1595 ],
1596 ))
1597 .optional();
1598 assert!(type1.is_coercible_to(&type2));
1599 assert!(!type2.is_coercible_to(&type1));
1600
1601 let type1: Type = Type::from(StructType::new(
1603 "Foo",
1604 [
1605 ("foo", PrimitiveType::String),
1606 ("bar", PrimitiveType::String),
1607 ("baz", PrimitiveType::Integer),
1608 ],
1609 ))
1610 .optional();
1611 let type2 = Type::from(StructType::new(
1612 "Foo",
1613 [
1614 ("foo", PrimitiveType::String),
1615 ("bar", PrimitiveType::String),
1616 ("baz", PrimitiveType::Integer),
1617 ],
1618 ))
1619 .optional();
1620 assert!(type1.is_coercible_to(&type2));
1621 assert!(type2.is_coercible_to(&type1));
1622
1623 let type1: Type = StructType::new(
1625 "Foo",
1626 [
1627 ("foo", PrimitiveType::String),
1628 ("bar", PrimitiveType::String),
1629 ("baz", PrimitiveType::Integer),
1630 ],
1631 )
1632 .into();
1633 let type2 = StructType::new(
1634 "Bar",
1635 [
1636 ("foo", PrimitiveType::File),
1637 ("bar", PrimitiveType::Directory),
1638 ("baz", PrimitiveType::Float),
1639 ],
1640 )
1641 .into();
1642 assert!(type1.is_coercible_to(&type2));
1643 assert!(!type2.is_coercible_to(&type1));
1644
1645 let type1: Type = StructType::new(
1647 "Foo",
1648 [
1649 ("foo", PrimitiveType::String),
1650 ("bar", PrimitiveType::String),
1651 ("baz", PrimitiveType::Integer),
1652 ],
1653 )
1654 .into();
1655 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1656 assert!(!type1.is_coercible_to(&type2));
1657 assert!(!type2.is_coercible_to(&type1));
1658
1659 let type1: Type = StructType::new(
1661 "Foo",
1662 [
1663 ("foo", PrimitiveType::String),
1664 ("bar", PrimitiveType::String),
1665 ("baz", PrimitiveType::String),
1666 ],
1667 )
1668 .into();
1669 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1670 assert!(type1.is_coercible_to(&type2));
1671
1672 let type1: Type = StructType::new(
1674 "Foo",
1675 [
1676 ("foo", PrimitiveType::String),
1677 ("bar", PrimitiveType::String),
1678 ("baz", PrimitiveType::String),
1679 ],
1680 )
1681 .into();
1682 let type2 = MapType::new(PrimitiveType::File, PrimitiveType::String).into();
1683 assert!(type1.is_coercible_to(&type2));
1684
1685 let type1: Type = StructType::new(
1687 "Foo",
1688 [
1689 ("foo", PrimitiveType::String),
1690 ("bar", PrimitiveType::Integer),
1691 ("baz", PrimitiveType::String),
1692 ],
1693 )
1694 .into();
1695 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1696 assert!(!type1.is_coercible_to(&type2));
1697
1698 let type1: Type = StructType::new(
1700 "Foo",
1701 [
1702 ("foo", PrimitiveType::String),
1703 ("bar", PrimitiveType::String),
1704 ("baz", PrimitiveType::String),
1705 ],
1706 )
1707 .into();
1708 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1709 assert!(!type1.is_coercible_to(&type2));
1710
1711 assert!(type1.is_coercible_to(&Type::Object));
1713
1714 assert!(type1.is_coercible_to(&Type::OptionalObject));
1716
1717 let type1: Type =
1719 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1720 assert!(type1.is_coercible_to(&Type::OptionalObject));
1721
1722 assert!(!type1.is_coercible_to(&Type::Object));
1724 }
1725
1726 #[test]
1727 fn union_type_coercion() {
1728 for ty in [
1730 Type::from(PrimitiveType::Boolean),
1731 PrimitiveType::Directory.into(),
1732 PrimitiveType::File.into(),
1733 PrimitiveType::Float.into(),
1734 PrimitiveType::Integer.into(),
1735 PrimitiveType::String.into(),
1736 ] {
1737 assert!(Type::Union.is_coercible_to(&ty));
1738 assert!(Type::Union.is_coercible_to(&ty.optional()));
1739 assert!(ty.is_coercible_to(&Type::Union));
1740 }
1741
1742 for optional in [true, false] {
1743 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1745 let ty = if optional { ty.optional() } else { ty };
1746
1747 let coercible = Type::Union.is_coercible_to(&ty);
1748 assert!(coercible);
1749
1750 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1752 let ty = if optional { ty.optional() } else { ty };
1753 let coercible = Type::Union.is_coercible_to(&ty);
1754 assert!(coercible);
1755
1756 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1758 let ty = if optional { ty.optional() } else { ty };
1759 let coercible = Type::Union.is_coercible_to(&ty);
1760 assert!(coercible);
1761
1762 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1764 let ty = if optional { ty.optional() } else { ty };
1765 let coercible = Type::Union.is_coercible_to(&ty);
1766 assert!(coercible);
1767 }
1768 }
1769
1770 #[test]
1771 fn none_type_coercion() {
1772 for ty in [
1774 Type::from(PrimitiveType::Boolean),
1775 PrimitiveType::Directory.into(),
1776 PrimitiveType::File.into(),
1777 PrimitiveType::Float.into(),
1778 PrimitiveType::Integer.into(),
1779 PrimitiveType::String.into(),
1780 ] {
1781 assert!(!Type::None.is_coercible_to(&ty));
1782 assert!(Type::None.is_coercible_to(&ty.optional()));
1783 assert!(!ty.is_coercible_to(&Type::None));
1784 }
1785
1786 for optional in [true, false] {
1787 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1789 let ty = if optional { ty.optional() } else { ty };
1790 let coercible = Type::None.is_coercible_to(&ty);
1791 if optional {
1792 assert!(coercible);
1793 } else {
1794 assert!(!coercible);
1795 }
1796
1797 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1799 let ty = if optional { ty.optional() } else { ty };
1800 let coercible = Type::None.is_coercible_to(&ty);
1801 if optional {
1802 assert!(coercible);
1803 } else {
1804 assert!(!coercible);
1805 }
1806
1807 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1809 let ty = if optional { ty.optional() } else { ty };
1810 let coercible = Type::None.is_coercible_to(&ty);
1811 if optional {
1812 assert!(coercible);
1813 } else {
1814 assert!(!coercible);
1815 }
1816
1817 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1819 let ty = if optional { ty.optional() } else { ty };
1820 let coercible = Type::None.is_coercible_to(&ty);
1821 if optional {
1822 assert!(coercible);
1823 } else {
1824 assert!(!coercible);
1825 }
1826 }
1827 }
1828
1829 #[test]
1830 fn primitive_equality() {
1831 for ty in [
1832 Type::from(PrimitiveType::Boolean),
1833 PrimitiveType::Directory.into(),
1834 PrimitiveType::File.into(),
1835 PrimitiveType::Float.into(),
1836 PrimitiveType::Integer.into(),
1837 PrimitiveType::String.into(),
1838 ] {
1839 assert!(ty.eq(&ty));
1840 assert!(!ty.optional().eq(&ty));
1841 assert!(!ty.eq(&ty.optional()));
1842 assert!(ty.optional().eq(&ty.optional()));
1843 assert!(!ty.eq(&Type::Object));
1844 assert!(!ty.eq(&Type::OptionalObject));
1845 assert!(!ty.eq(&Type::Union));
1846 assert!(!ty.eq(&Type::None));
1847 }
1848 }
1849
1850 #[test]
1851 fn array_equality() {
1852 let a: Type = ArrayType::new(PrimitiveType::String).into();
1854 let b: Type = ArrayType::new(PrimitiveType::String).into();
1855 assert!(a.eq(&b));
1856 assert!(!a.optional().eq(&b));
1857 assert!(!a.eq(&b.optional()));
1858 assert!(a.optional().eq(&b.optional()));
1859
1860 let a: Type = ArrayType::new(a).into();
1862 let b: Type = ArrayType::new(b).into();
1863 assert!(a.eq(&b));
1864
1865 let a: Type = ArrayType::non_empty(a).into();
1867 let b: Type = ArrayType::non_empty(b).into();
1868 assert!(a.eq(&b));
1869
1870 let a: Type = ArrayType::new(PrimitiveType::String).into();
1872 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1873 assert!(!a.eq(&b));
1874
1875 let a: Type = ArrayType::new(PrimitiveType::String).into();
1877 let b: Type = ArrayType::new(PrimitiveType::Integer).into();
1878 assert!(!a.eq(&b));
1879
1880 assert!(!a.eq(&Type::Object));
1881 assert!(!a.eq(&Type::OptionalObject));
1882 assert!(!a.eq(&Type::Union));
1883 assert!(!a.eq(&Type::None));
1884 }
1885
1886 #[test]
1887 fn pair_equality() {
1888 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1890 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1891 assert!(a.eq(&b));
1892 assert!(!a.optional().eq(&b));
1893 assert!(!a.eq(&b.optional()));
1894 assert!(a.optional().eq(&b.optional()));
1895
1896 let a: Type = PairType::new(a.clone(), a).into();
1899 let b: Type = PairType::new(b.clone(), b).into();
1900 assert!(a.eq(&b));
1901
1902 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1904 let b: Type =
1905 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1906 assert!(!a.eq(&b));
1907
1908 assert!(!a.eq(&Type::Object));
1909 assert!(!a.eq(&Type::OptionalObject));
1910 assert!(!a.eq(&Type::Union));
1911 assert!(!a.eq(&Type::None));
1912 }
1913
1914 #[test]
1915 fn map_equality() {
1916 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1918 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1919 assert!(a.eq(&b));
1920 assert!(!a.optional().eq(&b));
1921 assert!(!a.eq(&b.optional()));
1922 assert!(a.optional().eq(&b.optional()));
1923
1924 let a: Type = MapType::new(PrimitiveType::File, a).into();
1926 let b = MapType::new(PrimitiveType::File, b).into();
1927 assert!(a.eq(&b));
1928
1929 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1931 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1932 assert!(!a.eq(&b));
1933
1934 assert!(!a.eq(&Type::Object));
1935 assert!(!a.eq(&Type::OptionalObject));
1936 assert!(!a.eq(&Type::Union));
1937 assert!(!a.eq(&Type::None));
1938 }
1939
1940 #[test]
1941 fn struct_equality() {
1942 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1943 assert!(a.eq(&a));
1944 assert!(!a.optional().eq(&a));
1945 assert!(!a.eq(&a.optional()));
1946 assert!(a.optional().eq(&a.optional()));
1947
1948 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1949 assert!(a.eq(&b));
1950 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1951 assert!(!a.eq(&b));
1952 }
1953
1954 #[test]
1955 fn object_equality() {
1956 assert!(Type::Object.eq(&Type::Object));
1957 assert!(!Type::OptionalObject.eq(&Type::Object));
1958 assert!(!Type::Object.eq(&Type::OptionalObject));
1959 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1960 }
1961
1962 #[test]
1963 fn union_equality() {
1964 assert!(Type::Union.eq(&Type::Union));
1965 assert!(!Type::None.eq(&Type::Union));
1966 assert!(!Type::Union.eq(&Type::None));
1967 assert!(Type::None.eq(&Type::None));
1968 }
1969}