1use std::collections::HashSet;
4use std::fmt;
5use std::sync::Arc;
6
7use indexmap::IndexMap;
8use wdl_ast::Diagnostic;
9use wdl_ast::Ident;
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: &Ident) -> 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, Hash)]
129pub enum PromotionKind {
130 Scatter,
132 Conditional,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
138pub enum Type {
139 Primitive(PrimitiveType, bool),
143 Compound(CompoundType, bool),
147 Object,
149 OptionalObject,
151 Union,
157 None,
159 Task,
162 Hints,
165 Input,
168 Output,
171 Call(CallType),
173}
174
175impl Type {
176 pub fn as_primitive(&self) -> Option<PrimitiveType> {
180 match self {
181 Self::Primitive(ty, _) => Some(*ty),
182 _ => None,
183 }
184 }
185
186 pub fn as_compound(&self) -> Option<&CompoundType> {
190 match self {
191 Self::Compound(ty, _) => Some(ty),
192 _ => None,
193 }
194 }
195
196 pub fn as_array(&self) -> Option<&ArrayType> {
200 match self {
201 Self::Compound(CompoundType::Array(ty), _) => Some(ty),
202 _ => None,
203 }
204 }
205
206 pub fn as_pair(&self) -> Option<&PairType> {
210 match self {
211 Self::Compound(CompoundType::Pair(ty), _) => Some(ty),
212 _ => None,
213 }
214 }
215
216 pub fn as_map(&self) -> Option<&MapType> {
220 match self {
221 Self::Compound(CompoundType::Map(ty), _) => Some(ty),
222 _ => None,
223 }
224 }
225
226 pub fn as_struct(&self) -> Option<&StructType> {
230 match self {
231 Self::Compound(CompoundType::Struct(ty), _) => Some(ty),
232 _ => None,
233 }
234 }
235
236 pub fn is_union(&self) -> bool {
238 matches!(self, Type::Union)
239 }
240
241 pub fn is_none(&self) -> bool {
243 matches!(self, Type::None)
244 }
245
246 pub fn promote(&self, kind: PromotionKind) -> Self {
248 if let Self::Call(ty) = self {
250 return Self::Call(ty.promote(kind));
251 }
252
253 match kind {
254 PromotionKind::Scatter => Type::Compound(ArrayType::new(self.clone()).into(), false),
255 PromotionKind::Conditional => self.optional(),
256 }
257 }
258
259 pub fn common_type(&self, other: &Type) -> Option<Type> {
263 if other.is_union() {
265 return Some(self.clone());
266 }
267
268 if self.is_union() {
270 return Some(other.clone());
271 }
272
273 if other.is_none() {
276 return Some(self.optional());
277 }
278
279 if self.is_none() {
281 return Some(other.optional());
282 }
283
284 if other.is_coercible_to(self) {
286 return Some(self.clone());
287 }
288
289 if self.is_coercible_to(other) {
291 return Some(other.clone());
292 }
293
294 if let (Some(this), Some(other)) = (self.as_compound(), other.as_compound()) {
296 if let Some(ty) = this.common_type(other) {
297 return Some(Self::Compound(ty, self.is_optional()));
298 }
299 }
300
301 None
302 }
303}
304
305impl fmt::Display for Type {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 match self {
308 Self::Primitive(ty, optional) => {
309 ty.fmt(f)?;
310 if *optional { write!(f, "?") } else { Ok(()) }
311 }
312 Self::Compound(ty, optional) => {
313 ty.fmt(f)?;
314 if *optional { write!(f, "?") } else { Ok(()) }
315 }
316 Self::Object => {
317 write!(f, "Object")
318 }
319 Self::OptionalObject => {
320 write!(f, "Object?")
321 }
322 Self::Union => write!(f, "Union"),
323 Self::None => write!(f, "None"),
324 Self::Task => write!(f, "task"),
325 Self::Hints => write!(f, "hints"),
326 Self::Input => write!(f, "input"),
327 Self::Output => write!(f, "output"),
328 Self::Call(ty) => ty.fmt(f),
329 }
330 }
331}
332
333impl Optional for Type {
334 fn is_optional(&self) -> bool {
335 match self {
336 Self::Primitive(_, optional) => *optional,
337 Self::Compound(_, optional) => *optional,
338 Self::OptionalObject | Self::None => true,
339 Self::Object
340 | Self::Union
341 | Self::Task
342 | Self::Hints
343 | Self::Input
344 | Self::Output
345 | Self::Call(_) => false,
346 }
347 }
348
349 fn optional(&self) -> Self {
350 match self {
351 Self::Primitive(ty, _) => Self::Primitive(*ty, true),
352 Self::Compound(ty, _) => Self::Compound(ty.clone(), true),
353 Self::Object => Self::OptionalObject,
354 Self::Union => Self::None,
355 ty => ty.clone(),
356 }
357 }
358
359 fn require(&self) -> Self {
360 match self {
361 Self::Primitive(ty, _) => Self::Primitive(*ty, false),
362 Self::Compound(ty, _) => Self::Compound(ty.clone(), false),
363 Self::OptionalObject => Self::Object,
364 Self::None => Self::Union,
365 ty => ty.clone(),
366 }
367 }
368}
369
370impl Coercible for Type {
371 fn is_coercible_to(&self, target: &Self) -> bool {
372 if self.eq(target) {
373 return true;
374 }
375
376 match (self, target) {
377 (Self::Primitive(src, src_opt), Self::Primitive(target, target_opt)) => {
378 if *src_opt && !*target_opt {
380 return false;
381 }
382
383 src.is_coercible_to(target)
384 }
385 (Self::Compound(src, src_opt), Self::Compound(target, target_opt)) => {
386 if *src_opt && !*target_opt {
388 return false;
389 }
390
391 src.is_coercible_to(target)
392 }
393
394 (Self::Object, Self::Object)
396 | (Self::Object, Self::OptionalObject)
397 | (Self::OptionalObject, Self::OptionalObject) => true,
398
399 (Self::Compound(src, false), Self::Object)
402 | (Self::Compound(src, false), Self::OptionalObject)
403 | (Self::Compound(src, _), Self::OptionalObject) => match src {
404 CompoundType::Map(src) => {
405 matches!(src.key_type, Type::Primitive(PrimitiveType::String, _))
406 }
407 CompoundType::Struct(_) => true,
408 _ => false,
409 },
410
411 (Self::Object, Self::Compound(target, _))
416 | (Self::OptionalObject, Self::Compound(target, true)) => {
417 match target {
418 CompoundType::Map(target) => {
419 matches!(target.key_type, Type::Primitive(PrimitiveType::String, _))
420 }
421 CompoundType::Struct(_) => {
422 true
424 }
425 _ => false,
426 }
427 }
428
429 (Self::Union, _) | (_, Self::Union) => true,
431
432 (Self::None, ty) if ty.is_optional() => true,
434
435 _ => false,
437 }
438 }
439}
440
441impl From<PrimitiveType> for Type {
442 fn from(value: PrimitiveType) -> Self {
443 Self::Primitive(value, false)
444 }
445}
446
447impl From<CompoundType> for Type {
448 fn from(value: CompoundType) -> Self {
449 Self::Compound(value, false)
450 }
451}
452
453impl From<ArrayType> for Type {
454 fn from(value: ArrayType) -> Self {
455 Self::Compound(value.into(), false)
456 }
457}
458
459impl From<PairType> for Type {
460 fn from(value: PairType) -> Self {
461 Self::Compound(value.into(), false)
462 }
463}
464
465impl From<MapType> for Type {
466 fn from(value: MapType) -> Self {
467 Self::Compound(value.into(), false)
468 }
469}
470
471impl From<StructType> for Type {
472 fn from(value: StructType) -> Self {
473 Self::Compound(value.into(), false)
474 }
475}
476
477impl From<CallType> for Type {
478 fn from(value: CallType) -> Self {
479 Self::Call(value)
480 }
481}
482
483#[derive(Debug, Clone, PartialEq, Eq)]
485pub enum CompoundType {
486 Array(Arc<ArrayType>),
488 Pair(Arc<PairType>),
490 Map(Arc<MapType>),
492 Struct(Arc<StructType>),
494}
495
496impl CompoundType {
497 pub fn as_array(&self) -> Option<&ArrayType> {
501 match self {
502 Self::Array(ty) => Some(ty),
503 _ => None,
504 }
505 }
506
507 pub fn as_pair(&self) -> Option<&PairType> {
511 match self {
512 Self::Pair(ty) => Some(ty),
513 _ => None,
514 }
515 }
516
517 pub fn as_map(&self) -> Option<&MapType> {
521 match self {
522 Self::Map(ty) => Some(ty),
523 _ => None,
524 }
525 }
526
527 pub fn as_struct(&self) -> Option<&StructType> {
531 match self {
532 Self::Struct(ty) => Some(ty),
533 _ => None,
534 }
535 }
536
537 fn common_type(&self, other: &Self) -> Option<CompoundType> {
542 match (self, other) {
545 (Self::Array(this), Self::Array(other)) => {
546 let element_type = this.element_type.common_type(&other.element_type)?;
547 Some(ArrayType::new(element_type).into())
548 }
549 (Self::Pair(this), Self::Pair(other)) => {
550 let left_type = this.left_type.common_type(&other.left_type)?;
551 let right_type = this.right_type.common_type(&other.right_type)?;
552 Some(PairType::new(left_type, right_type).into())
553 }
554 (Self::Map(this), Self::Map(other)) => {
555 let key_type = this.key_type.common_type(&other.key_type)?;
556 let value_type = this.value_type.common_type(&other.value_type)?;
557 Some(MapType::new(key_type, value_type).into())
558 }
559 _ => None,
560 }
561 }
562}
563
564impl fmt::Display for CompoundType {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 match self {
567 Self::Array(ty) => ty.fmt(f),
568 Self::Pair(ty) => ty.fmt(f),
569 Self::Map(ty) => ty.fmt(f),
570 Self::Struct(ty) => ty.fmt(f),
571 }
572 }
573}
574
575impl Coercible for CompoundType {
576 fn is_coercible_to(&self, target: &Self) -> bool {
577 match (self, target) {
578 (Self::Array(src), Self::Array(target)) => src.is_coercible_to(target),
581
582 (Self::Pair(src), Self::Pair(target)) => src.is_coercible_to(target),
585
586 (Self::Map(src), Self::Map(target)) => src.is_coercible_to(target),
589
590 (Self::Struct(src), Self::Struct(target)) => src.is_coercible_to(target),
593
594 (Self::Map(src), Self::Struct(target)) => {
597 if !matches!(src.key_type, Type::Primitive(PrimitiveType::String, _)) {
598 return false;
599 }
600
601 if !target
603 .members
604 .values()
605 .all(|ty| src.value_type.is_coercible_to(ty))
606 {
607 return false;
608 }
609
610 true
612 }
613
614 (Self::Struct(src), Self::Map(target)) => {
617 if !matches!(target.key_type, Type::Primitive(PrimitiveType::String, _)) {
618 return false;
619 }
620
621 if !src
623 .members
624 .values()
625 .all(|ty| ty.is_coercible_to(&target.value_type))
626 {
627 return false;
628 }
629
630 true
631 }
632
633 _ => false,
634 }
635 }
636}
637
638impl From<ArrayType> for CompoundType {
639 fn from(value: ArrayType) -> Self {
640 Self::Array(value.into())
641 }
642}
643
644impl From<PairType> for CompoundType {
645 fn from(value: PairType) -> Self {
646 Self::Pair(value.into())
647 }
648}
649
650impl From<MapType> for CompoundType {
651 fn from(value: MapType) -> Self {
652 Self::Map(value.into())
653 }
654}
655
656impl From<StructType> for CompoundType {
657 fn from(value: StructType) -> Self {
658 Self::Struct(value.into())
659 }
660}
661
662#[derive(Debug, Clone, PartialEq, Eq)]
664pub struct ArrayType {
665 element_type: Type,
667 non_empty: bool,
672}
673
674impl ArrayType {
675 pub fn new(element_type: impl Into<Type>) -> Self {
677 Self {
678 element_type: element_type.into(),
679 non_empty: false,
680 }
681 }
682
683 pub fn non_empty(element_type: impl Into<Type>) -> Self {
685 Self {
686 element_type: element_type.into(),
687 non_empty: true,
688 }
689 }
690
691 pub fn element_type(&self) -> &Type {
693 &self.element_type
694 }
695
696 pub fn is_non_empty(&self) -> bool {
698 self.non_empty
699 }
700}
701
702impl fmt::Display for ArrayType {
703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704 write!(f, "Array[{ty}]", ty = self.element_type)?;
705
706 if self.non_empty {
707 write!(f, "+")?;
708 }
709
710 Ok(())
711 }
712}
713
714impl Coercible for ArrayType {
715 fn is_coercible_to(&self, target: &Self) -> bool {
716 self.element_type.is_coercible_to(&target.element_type)
717 }
718}
719
720#[derive(Debug, Clone, PartialEq, Eq)]
722pub struct PairType {
723 left_type: Type,
725 right_type: Type,
727}
728
729impl PairType {
730 pub fn new(left_type: impl Into<Type>, right_type: impl Into<Type>) -> Self {
732 Self {
733 left_type: left_type.into(),
734 right_type: right_type.into(),
735 }
736 }
737
738 pub fn left_type(&self) -> &Type {
740 &self.left_type
741 }
742
743 pub fn right_type(&self) -> &Type {
745 &self.right_type
746 }
747}
748
749impl fmt::Display for PairType {
750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
751 write!(
752 f,
753 "Pair[{left}, {right}]",
754 left = self.left_type,
755 right = self.right_type
756 )?;
757
758 Ok(())
759 }
760}
761
762impl Coercible for PairType {
763 fn is_coercible_to(&self, target: &Self) -> bool {
764 self.left_type.is_coercible_to(&target.left_type)
765 && self.right_type.is_coercible_to(&target.right_type)
766 }
767}
768
769#[derive(Debug, Clone, PartialEq, Eq)]
771pub struct MapType {
772 key_type: Type,
774 value_type: Type,
776}
777
778impl MapType {
779 pub fn new(key_type: impl Into<Type>, value_type: impl Into<Type>) -> Self {
781 Self {
782 key_type: key_type.into(),
783 value_type: value_type.into(),
784 }
785 }
786
787 pub fn key_type(&self) -> &Type {
789 &self.key_type
790 }
791
792 pub fn value_type(&self) -> &Type {
794 &self.value_type
795 }
796}
797
798impl fmt::Display for MapType {
799 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
800 write!(
801 f,
802 "Map[{key}, {value}]",
803 key = self.key_type,
804 value = self.value_type
805 )?;
806
807 Ok(())
808 }
809}
810
811impl Coercible for MapType {
812 fn is_coercible_to(&self, target: &Self) -> bool {
813 self.key_type.is_coercible_to(&target.key_type)
814 && self.value_type.is_coercible_to(&target.value_type)
815 }
816}
817
818#[derive(Debug, PartialEq, Eq)]
820pub struct StructType {
821 name: Arc<String>,
823 members: IndexMap<String, Type>,
825}
826
827impl StructType {
828 pub fn new<N, T>(name: impl Into<String>, members: impl IntoIterator<Item = (N, T)>) -> Self
830 where
831 N: Into<String>,
832 T: Into<Type>,
833 {
834 Self {
835 name: Arc::new(name.into()),
836 members: members
837 .into_iter()
838 .map(|(n, ty)| (n.into(), ty.into()))
839 .collect(),
840 }
841 }
842
843 pub fn name(&self) -> &Arc<String> {
845 &self.name
846 }
847
848 pub fn members(&self) -> &IndexMap<String, Type> {
850 &self.members
851 }
852}
853
854impl fmt::Display for StructType {
855 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
856 write!(f, "{name}", name = self.name)
857 }
858}
859
860impl Coercible for StructType {
861 fn is_coercible_to(&self, target: &Self) -> bool {
862 if self.members.len() != target.members.len() {
863 return false;
864 }
865
866 self.members.iter().all(|(k, v)| {
867 target
868 .members
869 .get(k)
870 .map(|target| v.is_coercible_to(target))
871 .unwrap_or(false)
872 })
873 }
874}
875
876#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
878pub enum CallKind {
879 Task,
881 Workflow,
883}
884
885impl fmt::Display for CallKind {
886 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887 match self {
888 Self::Task => write!(f, "task"),
889 Self::Workflow => write!(f, "workflow"),
890 }
891 }
892}
893
894#[derive(Debug, Clone, Eq)]
896pub struct CallType {
897 kind: CallKind,
899 namespace: Option<Arc<String>>,
901 name: Arc<String>,
903 specified: Arc<HashSet<String>>,
905 inputs: Arc<IndexMap<String, Input>>,
907 outputs: Arc<IndexMap<String, Output>>,
909}
910
911impl CallType {
912 pub fn new(
914 kind: CallKind,
915 name: impl Into<String>,
916 specified: Arc<HashSet<String>>,
917 inputs: Arc<IndexMap<String, Input>>,
918 outputs: Arc<IndexMap<String, Output>>,
919 ) -> Self {
920 Self {
921 kind,
922 namespace: None,
923 name: Arc::new(name.into()),
924 specified,
925 inputs,
926 outputs,
927 }
928 }
929
930 pub fn namespaced(
933 kind: CallKind,
934 namespace: impl Into<String>,
935 name: impl Into<String>,
936 specified: Arc<HashSet<String>>,
937 inputs: Arc<IndexMap<String, Input>>,
938 outputs: Arc<IndexMap<String, Output>>,
939 ) -> Self {
940 Self {
941 kind,
942 namespace: Some(Arc::new(namespace.into())),
943 name: Arc::new(name.into()),
944 specified,
945 inputs,
946 outputs,
947 }
948 }
949
950 pub fn kind(&self) -> CallKind {
952 self.kind
953 }
954
955 pub fn namespace(&self) -> Option<&str> {
959 self.namespace.as_ref().map(|ns| ns.as_str())
960 }
961
962 pub fn name(&self) -> &str {
964 &self.name
965 }
966
967 pub fn specified(&self) -> &HashSet<String> {
969 &self.specified
970 }
971
972 pub fn inputs(&self) -> &IndexMap<String, Input> {
974 &self.inputs
975 }
976
977 pub fn outputs(&self) -> &IndexMap<String, Output> {
979 &self.outputs
980 }
981
982 pub fn promote(&self, kind: PromotionKind) -> Self {
984 let mut ty = self.clone();
985 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
986 *output = Output::new(output.ty().promote(kind));
987 }
988
989 ty
990 }
991}
992
993impl Coercible for CallType {
994 fn is_coercible_to(&self, _: &Self) -> bool {
995 false
997 }
998}
999
1000impl fmt::Display for CallType {
1001 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1002 if let Some(ns) = &self.namespace {
1003 write!(
1004 f,
1005 "call to {kind} `{ns}.{name}`",
1006 kind = self.kind,
1007 name = self.name,
1008 )
1009 } else {
1010 write!(
1011 f,
1012 "call to {kind} `{name}`",
1013 kind = self.kind,
1014 name = self.name,
1015 )
1016 }
1017 }
1018}
1019
1020impl PartialEq for CallType {
1021 fn eq(&self, other: &Self) -> bool {
1022 std::ptr::eq(self, other)
1024 }
1025}
1026
1027#[cfg(test)]
1028mod test {
1029 use pretty_assertions::assert_eq;
1030
1031 use super::*;
1032
1033 #[test]
1034 fn primitive_type_display() {
1035 assert_eq!(PrimitiveType::Boolean.to_string(), "Boolean");
1036 assert_eq!(PrimitiveType::Integer.to_string(), "Int");
1037 assert_eq!(PrimitiveType::Float.to_string(), "Float");
1038 assert_eq!(PrimitiveType::String.to_string(), "String");
1039 assert_eq!(PrimitiveType::File.to_string(), "File");
1040 assert_eq!(PrimitiveType::Directory.to_string(), "Directory");
1041 assert_eq!(
1042 Type::from(PrimitiveType::Boolean).optional().to_string(),
1043 "Boolean?"
1044 );
1045 assert_eq!(
1046 Type::from(PrimitiveType::Integer).optional().to_string(),
1047 "Int?"
1048 );
1049 assert_eq!(
1050 Type::from(PrimitiveType::Float).optional().to_string(),
1051 "Float?"
1052 );
1053 assert_eq!(
1054 Type::from(PrimitiveType::String).optional().to_string(),
1055 "String?"
1056 );
1057 assert_eq!(
1058 Type::from(PrimitiveType::File).optional().to_string(),
1059 "File?"
1060 );
1061 assert_eq!(
1062 Type::from(PrimitiveType::Directory).optional().to_string(),
1063 "Directory?"
1064 );
1065 }
1066
1067 #[test]
1068 fn array_type_display() {
1069 assert_eq!(
1070 ArrayType::new(PrimitiveType::String).to_string(),
1071 "Array[String]"
1072 );
1073 assert_eq!(
1074 ArrayType::non_empty(PrimitiveType::String).to_string(),
1075 "Array[String]+"
1076 );
1077
1078 let ty: Type = ArrayType::new(ArrayType::new(PrimitiveType::String)).into();
1079 assert_eq!(ty.to_string(), "Array[Array[String]]");
1080
1081 let ty = Type::from(ArrayType::non_empty(
1082 Type::from(ArrayType::non_empty(
1083 Type::from(PrimitiveType::String).optional(),
1084 ))
1085 .optional(),
1086 ))
1087 .optional();
1088 assert_eq!(ty.to_string(), "Array[Array[String?]+?]+?");
1089 }
1090
1091 #[test]
1092 fn pair_type_display() {
1093 assert_eq!(
1094 PairType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1095 "Pair[String, Boolean]"
1096 );
1097
1098 let ty: Type = PairType::new(
1099 ArrayType::new(PrimitiveType::String),
1100 ArrayType::new(PrimitiveType::String),
1101 )
1102 .into();
1103 assert_eq!(ty.to_string(), "Pair[Array[String], Array[String]]");
1104
1105 let ty = Type::from(PairType::new(
1106 Type::from(ArrayType::non_empty(
1107 Type::from(PrimitiveType::File).optional(),
1108 ))
1109 .optional(),
1110 Type::from(ArrayType::non_empty(
1111 Type::from(PrimitiveType::File).optional(),
1112 ))
1113 .optional(),
1114 ))
1115 .optional();
1116 assert_eq!(ty.to_string(), "Pair[Array[File?]+?, Array[File?]+?]?");
1117 }
1118
1119 #[test]
1120 fn map_type_display() {
1121 assert_eq!(
1122 MapType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1123 "Map[String, Boolean]"
1124 );
1125
1126 let ty: Type = MapType::new(
1127 PrimitiveType::Boolean,
1128 ArrayType::new(PrimitiveType::String),
1129 )
1130 .into();
1131 assert_eq!(ty.to_string(), "Map[Boolean, Array[String]]");
1132
1133 let ty: Type = Type::from(MapType::new(
1134 PrimitiveType::String,
1135 Type::from(ArrayType::non_empty(
1136 Type::from(PrimitiveType::File).optional(),
1137 ))
1138 .optional(),
1139 ))
1140 .optional();
1141 assert_eq!(ty.to_string(), "Map[String, Array[File?]+?]?");
1142 }
1143
1144 #[test]
1145 fn struct_type_display() {
1146 assert_eq!(
1147 StructType::new("Foobar", std::iter::empty::<(String, Type)>()).to_string(),
1148 "Foobar"
1149 );
1150 }
1151
1152 #[test]
1153 fn object_type_display() {
1154 assert_eq!(Type::Object.to_string(), "Object");
1155 assert_eq!(Type::OptionalObject.to_string(), "Object?");
1156 }
1157
1158 #[test]
1159 fn union_type_display() {
1160 assert_eq!(Type::Union.to_string(), "Union");
1161 }
1162
1163 #[test]
1164 fn none_type_display() {
1165 assert_eq!(Type::None.to_string(), "None");
1166 }
1167
1168 #[test]
1169 fn primitive_type_coercion() {
1170 for ty in [
1173 Type::from(PrimitiveType::Boolean),
1174 PrimitiveType::Directory.into(),
1175 PrimitiveType::File.into(),
1176 PrimitiveType::Float.into(),
1177 PrimitiveType::Integer.into(),
1178 PrimitiveType::String.into(),
1179 ] {
1180 assert!(ty.is_coercible_to(&ty));
1181 assert!(ty.optional().is_coercible_to(&ty.optional()));
1182 assert!(ty.is_coercible_to(&ty.optional()));
1183 assert!(!ty.optional().is_coercible_to(&ty));
1184 }
1185
1186 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::File));
1188 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::Directory));
1189 assert!(PrimitiveType::Integer.is_coercible_to(&PrimitiveType::Float));
1190 assert!(PrimitiveType::File.is_coercible_to(&PrimitiveType::String));
1191 assert!(PrimitiveType::Directory.is_coercible_to(&PrimitiveType::String));
1192 assert!(!PrimitiveType::Float.is_coercible_to(&PrimitiveType::Integer));
1193 }
1194
1195 #[test]
1196 fn object_type_coercion() {
1197 assert!(Type::Object.is_coercible_to(&Type::Object));
1198 assert!(Type::Object.is_coercible_to(&Type::OptionalObject));
1199 assert!(Type::OptionalObject.is_coercible_to(&Type::OptionalObject));
1200 assert!(!Type::OptionalObject.is_coercible_to(&Type::Object));
1201
1202 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1204 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1205
1206 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1208 assert!(!Type::Object.is_coercible_to(&ty));
1209
1210 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1212 assert!(Type::Object.is_coercible_to(&ty));
1213
1214 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1216 assert!(Type::OptionalObject.is_coercible_to(&ty));
1217
1218 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1220 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1221
1222 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1224 assert!(Type::Object.is_coercible_to(&ty));
1225
1226 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1228 assert!(Type::Object.is_coercible_to(&ty));
1229
1230 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1232 assert!(Type::OptionalObject.is_coercible_to(&ty));
1233
1234 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1236 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1237 }
1238
1239 #[test]
1240 fn array_type_coercion() {
1241 assert!(
1243 ArrayType::new(PrimitiveType::String)
1244 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1245 );
1246 assert!(
1247 ArrayType::new(PrimitiveType::File)
1248 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1249 );
1250 assert!(
1251 ArrayType::new(PrimitiveType::String)
1252 .is_coercible_to(&ArrayType::new(PrimitiveType::File))
1253 );
1254
1255 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1257 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1258 assert!(type1.is_coercible_to(&type2));
1259 assert!(!type2.is_coercible_to(&type1));
1260
1261 let type1: Type = ArrayType::new(type1).into();
1263 let type2 = ArrayType::new(type2).into();
1264 assert!(type1.is_coercible_to(&type2));
1265 assert!(!type2.is_coercible_to(&type1));
1266
1267 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1269 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1270 assert!(type1.is_coercible_to(&type2));
1271 assert!(!type2.is_coercible_to(&type1));
1272
1273 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1275 let type2 = ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
1276 assert!(type1.is_coercible_to(&type2));
1277 assert!(!type2.is_coercible_to(&type1));
1278
1279 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1281 let type2 = ArrayType::new(PrimitiveType::String).into();
1282 assert!(type1.is_coercible_to(&type2));
1283 assert!(type2.is_coercible_to(&type1));
1284
1285 let type1 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1287 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1288 assert!(type1.is_coercible_to(&type2));
1289 assert!(type2.is_coercible_to(&type1));
1290
1291 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1293 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1294 assert!(type1.is_coercible_to(&type2));
1295 assert!(!type2.is_coercible_to(&type1));
1296 }
1297
1298 #[test]
1299 fn pair_type_coercion() {
1300 assert!(
1302 PairType::new(PrimitiveType::String, PrimitiveType::String)
1303 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1304 );
1305 assert!(
1306 PairType::new(PrimitiveType::String, PrimitiveType::String).is_coercible_to(
1307 &PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1308 )
1309 );
1310 assert!(
1311 PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1312 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1313 );
1314
1315 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1317 let type2 = PairType::new(
1318 Type::from(PrimitiveType::File).optional(),
1319 Type::from(PrimitiveType::Directory).optional(),
1320 )
1321 .into();
1322 assert!(type1.is_coercible_to(&type2));
1323 assert!(!type2.is_coercible_to(&type1));
1324
1325 let type1: Type = PairType::new(type1.clone(), type1).into();
1327 let type2 = PairType::new(type2.clone(), type2).into();
1328 assert!(type1.is_coercible_to(&type2));
1329 assert!(!type2.is_coercible_to(&type1));
1330
1331 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1333 let type2 = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1334 assert!(type1.is_coercible_to(&type2));
1335 assert!(type2.is_coercible_to(&type1));
1336
1337 let type1 =
1339 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1340 let type2 =
1341 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1342 assert!(type1.is_coercible_to(&type2));
1343 assert!(type2.is_coercible_to(&type1));
1344
1345 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1347 let type2 =
1348 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1349 assert!(type1.is_coercible_to(&type2));
1350 assert!(!type2.is_coercible_to(&type1));
1351 }
1352
1353 #[test]
1354 fn map_type_coercion() {
1355 assert!(
1357 MapType::new(PrimitiveType::String, PrimitiveType::String)
1358 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1359 );
1360 assert!(
1361 MapType::new(PrimitiveType::String, PrimitiveType::String)
1362 .is_coercible_to(&MapType::new(PrimitiveType::File, PrimitiveType::Directory))
1363 );
1364 assert!(
1365 MapType::new(PrimitiveType::File, PrimitiveType::Directory)
1366 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1367 );
1368
1369 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1371 let type2 = MapType::new(
1372 Type::from(PrimitiveType::File).optional(),
1373 Type::from(PrimitiveType::Directory).optional(),
1374 )
1375 .into();
1376 assert!(type1.is_coercible_to(&type2));
1377 assert!(!type2.is_coercible_to(&type1));
1378
1379 let type1: Type = MapType::new(PrimitiveType::String, type1).into();
1381 let type2 = MapType::new(PrimitiveType::Directory, type2).into();
1382 assert!(type1.is_coercible_to(&type2));
1383 assert!(!type2.is_coercible_to(&type1));
1384
1385 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1387 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1388 assert!(type1.is_coercible_to(&type2));
1389 assert!(type2.is_coercible_to(&type1));
1390
1391 let type1: Type =
1393 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1394 let type2: Type =
1395 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1396 assert!(type1.is_coercible_to(&type2));
1397 assert!(type2.is_coercible_to(&type1));
1398
1399 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1401 let type2 =
1402 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1403 assert!(type1.is_coercible_to(&type2));
1404 assert!(!type2.is_coercible_to(&type1));
1405
1406 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1408 let type2 = StructType::new("Foo", [
1409 ("foo", PrimitiveType::Integer),
1410 ("bar", PrimitiveType::Integer),
1411 ("baz", PrimitiveType::Integer),
1412 ])
1413 .into();
1414 assert!(type1.is_coercible_to(&type2));
1415
1416 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1418 let type2 = StructType::new("Foo", [
1419 ("foo", PrimitiveType::Integer),
1420 ("bar", PrimitiveType::String),
1421 ("baz", PrimitiveType::Integer),
1422 ])
1423 .into();
1424 assert!(!type1.is_coercible_to(&type2));
1425
1426 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1428 let type2 = StructType::new("Foo", [
1429 ("foo", PrimitiveType::Integer),
1430 ("bar", PrimitiveType::Integer),
1431 ("baz", PrimitiveType::Integer),
1432 ])
1433 .into();
1434 assert!(!type1.is_coercible_to(&type2));
1435
1436 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1438 assert!(type1.is_coercible_to(&Type::Object));
1439
1440 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1442 assert!(type1.is_coercible_to(&Type::OptionalObject));
1443
1444 let type1: Type =
1446 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1447 assert!(type1.is_coercible_to(&Type::OptionalObject));
1448
1449 let type1: Type =
1451 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1452 assert!(!type1.is_coercible_to(&Type::Object));
1453
1454 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1456 assert!(!type1.is_coercible_to(&Type::Object));
1457 }
1458
1459 #[test]
1460 fn struct_type_coercion() {
1461 let type1: Type = StructType::new("Foo", [
1463 ("foo", PrimitiveType::String),
1464 ("bar", PrimitiveType::String),
1465 ("baz", PrimitiveType::Integer),
1466 ])
1467 .into();
1468 let type2 = StructType::new("Foo", [
1469 ("foo", PrimitiveType::String),
1470 ("bar", PrimitiveType::String),
1471 ("baz", PrimitiveType::Integer),
1472 ])
1473 .into();
1474 assert!(type1.is_coercible_to(&type2));
1475 assert!(type2.is_coercible_to(&type1));
1476
1477 let type1: Type = StructType::new("Foo", [
1479 ("foo", PrimitiveType::String),
1480 ("bar", PrimitiveType::String),
1481 ("baz", PrimitiveType::Integer),
1482 ])
1483 .into();
1484 let type2 = Type::from(StructType::new("Foo", [
1485 ("foo", PrimitiveType::String),
1486 ("bar", PrimitiveType::String),
1487 ("baz", PrimitiveType::Integer),
1488 ]))
1489 .optional();
1490 assert!(type1.is_coercible_to(&type2));
1491 assert!(!type2.is_coercible_to(&type1));
1492
1493 let type1: Type = Type::from(StructType::new("Foo", [
1495 ("foo", PrimitiveType::String),
1496 ("bar", PrimitiveType::String),
1497 ("baz", PrimitiveType::Integer),
1498 ]))
1499 .optional();
1500 let type2 = Type::from(StructType::new("Foo", [
1501 ("foo", PrimitiveType::String),
1502 ("bar", PrimitiveType::String),
1503 ("baz", PrimitiveType::Integer),
1504 ]))
1505 .optional();
1506 assert!(type1.is_coercible_to(&type2));
1507 assert!(type2.is_coercible_to(&type1));
1508
1509 let type1: Type = StructType::new("Foo", [
1511 ("foo", PrimitiveType::String),
1512 ("bar", PrimitiveType::String),
1513 ("baz", PrimitiveType::Integer),
1514 ])
1515 .into();
1516 let type2 = StructType::new("Bar", [
1517 ("foo", PrimitiveType::File),
1518 ("bar", PrimitiveType::Directory),
1519 ("baz", PrimitiveType::Float),
1520 ])
1521 .into();
1522 assert!(type1.is_coercible_to(&type2));
1523 assert!(!type2.is_coercible_to(&type1));
1524
1525 let type1: Type = StructType::new("Foo", [
1527 ("foo", PrimitiveType::String),
1528 ("bar", PrimitiveType::String),
1529 ("baz", PrimitiveType::Integer),
1530 ])
1531 .into();
1532 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1533 assert!(!type1.is_coercible_to(&type2));
1534 assert!(!type2.is_coercible_to(&type1));
1535
1536 let type1: Type = StructType::new("Foo", [
1538 ("foo", PrimitiveType::String),
1539 ("bar", PrimitiveType::String),
1540 ("baz", PrimitiveType::String),
1541 ])
1542 .into();
1543 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1544 assert!(type1.is_coercible_to(&type2));
1545
1546 let type1: Type = StructType::new("Foo", [
1548 ("foo", PrimitiveType::String),
1549 ("bar", PrimitiveType::Integer),
1550 ("baz", PrimitiveType::String),
1551 ])
1552 .into();
1553 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1554 assert!(!type1.is_coercible_to(&type2));
1555
1556 let type1: Type = StructType::new("Foo", [
1558 ("foo", PrimitiveType::String),
1559 ("bar", PrimitiveType::String),
1560 ("baz", PrimitiveType::String),
1561 ])
1562 .into();
1563 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1564 assert!(!type1.is_coercible_to(&type2));
1565
1566 assert!(type1.is_coercible_to(&Type::Object));
1568
1569 assert!(type1.is_coercible_to(&Type::OptionalObject));
1571
1572 let type1: Type =
1574 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1575 assert!(type1.is_coercible_to(&Type::OptionalObject));
1576
1577 assert!(!type1.is_coercible_to(&Type::Object));
1579 }
1580
1581 #[test]
1582 fn union_type_coercion() {
1583 for ty in [
1585 Type::from(PrimitiveType::Boolean),
1586 PrimitiveType::Directory.into(),
1587 PrimitiveType::File.into(),
1588 PrimitiveType::Float.into(),
1589 PrimitiveType::Integer.into(),
1590 PrimitiveType::String.into(),
1591 ] {
1592 assert!(Type::Union.is_coercible_to(&ty));
1593 assert!(Type::Union.is_coercible_to(&ty.optional()));
1594 assert!(ty.is_coercible_to(&Type::Union));
1595 }
1596
1597 for optional in [true, false] {
1598 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1600 let ty = if optional { ty.optional() } else { ty };
1601
1602 let coercible = Type::Union.is_coercible_to(&ty);
1603 assert!(coercible);
1604
1605 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1607 let ty = if optional { ty.optional() } else { ty };
1608 let coercible = Type::Union.is_coercible_to(&ty);
1609 assert!(coercible);
1610
1611 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1613 let ty = if optional { ty.optional() } else { ty };
1614 let coercible = Type::Union.is_coercible_to(&ty);
1615 assert!(coercible);
1616
1617 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1619 let ty = if optional { ty.optional() } else { ty };
1620 let coercible = Type::Union.is_coercible_to(&ty);
1621 assert!(coercible);
1622 }
1623 }
1624
1625 #[test]
1626 fn none_type_coercion() {
1627 for ty in [
1629 Type::from(PrimitiveType::Boolean),
1630 PrimitiveType::Directory.into(),
1631 PrimitiveType::File.into(),
1632 PrimitiveType::Float.into(),
1633 PrimitiveType::Integer.into(),
1634 PrimitiveType::String.into(),
1635 ] {
1636 assert!(!Type::None.is_coercible_to(&ty));
1637 assert!(Type::None.is_coercible_to(&ty.optional()));
1638 assert!(!ty.is_coercible_to(&Type::None));
1639 }
1640
1641 for optional in [true, false] {
1642 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1644 let ty = if optional { ty.optional() } else { ty };
1645 let coercible = Type::None.is_coercible_to(&ty);
1646 if optional {
1647 assert!(coercible);
1648 } else {
1649 assert!(!coercible);
1650 }
1651
1652 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1654 let ty = if optional { ty.optional() } else { ty };
1655 let coercible = Type::None.is_coercible_to(&ty);
1656 if optional {
1657 assert!(coercible);
1658 } else {
1659 assert!(!coercible);
1660 }
1661
1662 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1664 let ty = if optional { ty.optional() } else { ty };
1665 let coercible = Type::None.is_coercible_to(&ty);
1666 if optional {
1667 assert!(coercible);
1668 } else {
1669 assert!(!coercible);
1670 }
1671
1672 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1674 let ty = if optional { ty.optional() } else { ty };
1675 let coercible = Type::None.is_coercible_to(&ty);
1676 if optional {
1677 assert!(coercible);
1678 } else {
1679 assert!(!coercible);
1680 }
1681 }
1682 }
1683
1684 #[test]
1685 fn primitive_equality() {
1686 for ty in [
1687 Type::from(PrimitiveType::Boolean),
1688 PrimitiveType::Directory.into(),
1689 PrimitiveType::File.into(),
1690 PrimitiveType::Float.into(),
1691 PrimitiveType::Integer.into(),
1692 PrimitiveType::String.into(),
1693 ] {
1694 assert!(ty.eq(&ty));
1695 assert!(!ty.optional().eq(&ty));
1696 assert!(!ty.eq(&ty.optional()));
1697 assert!(ty.optional().eq(&ty.optional()));
1698 assert!(!ty.eq(&Type::Object));
1699 assert!(!ty.eq(&Type::OptionalObject));
1700 assert!(!ty.eq(&Type::Union));
1701 assert!(!ty.eq(&Type::None));
1702 }
1703 }
1704
1705 #[test]
1706 fn array_equality() {
1707 let a: Type = ArrayType::new(PrimitiveType::String).into();
1709 let b: Type = ArrayType::new(PrimitiveType::String).into();
1710 assert!(a.eq(&b));
1711 assert!(!a.optional().eq(&b));
1712 assert!(!a.eq(&b.optional()));
1713 assert!(a.optional().eq(&b.optional()));
1714
1715 let a: Type = ArrayType::new(a).into();
1717 let b: Type = ArrayType::new(b).into();
1718 assert!(a.eq(&b));
1719
1720 let a: Type = ArrayType::non_empty(a).into();
1722 let b: Type = ArrayType::non_empty(b).into();
1723 assert!(a.eq(&b));
1724
1725 let a: Type = ArrayType::new(PrimitiveType::String).into();
1727 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1728 assert!(!a.eq(&b));
1729
1730 let a: Type = ArrayType::new(PrimitiveType::String).into();
1732 let b: Type = ArrayType::new(PrimitiveType::Integer).into();
1733 assert!(!a.eq(&b));
1734
1735 assert!(!a.eq(&Type::Object));
1736 assert!(!a.eq(&Type::OptionalObject));
1737 assert!(!a.eq(&Type::Union));
1738 assert!(!a.eq(&Type::None));
1739 }
1740
1741 #[test]
1742 fn pair_equality() {
1743 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1745 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1746 assert!(a.eq(&b));
1747 assert!(!a.optional().eq(&b));
1748 assert!(!a.eq(&b.optional()));
1749 assert!(a.optional().eq(&b.optional()));
1750
1751 let a: Type = PairType::new(a.clone(), a).into();
1754 let b: Type = PairType::new(b.clone(), b).into();
1755 assert!(a.eq(&b));
1756
1757 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1759 let b: Type =
1760 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1761 assert!(!a.eq(&b));
1762
1763 assert!(!a.eq(&Type::Object));
1764 assert!(!a.eq(&Type::OptionalObject));
1765 assert!(!a.eq(&Type::Union));
1766 assert!(!a.eq(&Type::None));
1767 }
1768
1769 #[test]
1770 fn map_equality() {
1771 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1773 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1774 assert!(a.eq(&b));
1775 assert!(!a.optional().eq(&b));
1776 assert!(!a.eq(&b.optional()));
1777 assert!(a.optional().eq(&b.optional()));
1778
1779 let a: Type = MapType::new(PrimitiveType::File, a).into();
1781 let b = MapType::new(PrimitiveType::File, b).into();
1782 assert!(a.eq(&b));
1783
1784 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1786 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1787 assert!(!a.eq(&b));
1788
1789 assert!(!a.eq(&Type::Object));
1790 assert!(!a.eq(&Type::OptionalObject));
1791 assert!(!a.eq(&Type::Union));
1792 assert!(!a.eq(&Type::None));
1793 }
1794
1795 #[test]
1796 fn struct_equality() {
1797 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1798 assert!(a.eq(&a));
1799 assert!(!a.optional().eq(&a));
1800 assert!(!a.eq(&a.optional()));
1801 assert!(a.optional().eq(&a.optional()));
1802
1803 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1804 assert!(a.eq(&b));
1805 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1806 assert!(!a.eq(&b));
1807 }
1808
1809 #[test]
1810 fn object_equality() {
1811 assert!(Type::Object.eq(&Type::Object));
1812 assert!(!Type::OptionalObject.eq(&Type::Object));
1813 assert!(!Type::Object.eq(&Type::OptionalObject));
1814 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1815 }
1816
1817 #[test]
1818 fn union_equality() {
1819 assert!(Type::Union.eq(&Type::Union));
1820 assert!(!Type::None.eq(&Type::Union));
1821 assert!(!Type::Union.eq(&Type::None));
1822 assert!(Type::None.eq(&Type::None));
1823 }
1824}