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, 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 as_call(&self) -> Option<&CallType> {
240 match self {
241 Self::Call(ty) => Some(ty),
242 _ => None,
243 }
244 }
245
246 pub fn is_union(&self) -> bool {
248 matches!(self, Type::Union)
249 }
250
251 pub fn is_none(&self) -> bool {
253 matches!(self, Type::None)
254 }
255
256 pub fn promote(&self, kind: PromotionKind) -> Self {
258 if let Self::Call(ty) = self {
260 return Self::Call(ty.promote(kind));
261 }
262
263 match kind {
264 PromotionKind::Scatter => Type::Compound(ArrayType::new(self.clone()).into(), false),
265 PromotionKind::Conditional => self.optional(),
266 }
267 }
268
269 pub fn common_type(&self, other: &Type) -> Option<Type> {
273 if other.is_union() {
275 return Some(self.clone());
276 }
277
278 if self.is_union() {
280 return Some(other.clone());
281 }
282
283 if other.is_none() {
286 return Some(self.optional());
287 }
288
289 if self.is_none() {
291 return Some(other.optional());
292 }
293
294 if other.is_coercible_to(self) {
296 return Some(self.clone());
297 }
298
299 if self.is_coercible_to(other) {
301 return Some(other.clone());
302 }
303
304 if let (Some(this), Some(other)) = (self.as_compound(), other.as_compound()) {
306 if let Some(ty) = this.common_type(other) {
307 return Some(Self::Compound(ty, self.is_optional()));
308 }
309 }
310
311 None
312 }
313}
314
315impl fmt::Display for Type {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 match self {
318 Self::Primitive(ty, optional) => {
319 ty.fmt(f)?;
320 if *optional { write!(f, "?") } else { Ok(()) }
321 }
322 Self::Compound(ty, optional) => {
323 ty.fmt(f)?;
324 if *optional { write!(f, "?") } else { Ok(()) }
325 }
326 Self::Object => {
327 write!(f, "Object")
328 }
329 Self::OptionalObject => {
330 write!(f, "Object?")
331 }
332 Self::Union => write!(f, "Union"),
333 Self::None => write!(f, "None"),
334 Self::Task => write!(f, "task"),
335 Self::Hints => write!(f, "hints"),
336 Self::Input => write!(f, "input"),
337 Self::Output => write!(f, "output"),
338 Self::Call(ty) => ty.fmt(f),
339 }
340 }
341}
342
343impl Optional for Type {
344 fn is_optional(&self) -> bool {
345 match self {
346 Self::Primitive(_, optional) => *optional,
347 Self::Compound(_, optional) => *optional,
348 Self::OptionalObject | Self::None => true,
349 Self::Object
350 | Self::Union
351 | Self::Task
352 | Self::Hints
353 | Self::Input
354 | Self::Output
355 | Self::Call(_) => false,
356 }
357 }
358
359 fn optional(&self) -> Self {
360 match self {
361 Self::Primitive(ty, _) => Self::Primitive(*ty, true),
362 Self::Compound(ty, _) => Self::Compound(ty.clone(), true),
363 Self::Object => Self::OptionalObject,
364 Self::Union => Self::None,
365 ty => ty.clone(),
366 }
367 }
368
369 fn require(&self) -> Self {
370 match self {
371 Self::Primitive(ty, _) => Self::Primitive(*ty, false),
372 Self::Compound(ty, _) => Self::Compound(ty.clone(), false),
373 Self::OptionalObject => Self::Object,
374 Self::None => Self::Union,
375 ty => ty.clone(),
376 }
377 }
378}
379
380impl Coercible for Type {
381 fn is_coercible_to(&self, target: &Self) -> bool {
382 if self.eq(target) {
383 return true;
384 }
385
386 match (self, target) {
387 (Self::Primitive(src, src_opt), Self::Primitive(target, target_opt)) => {
388 if *src_opt && !*target_opt {
390 return false;
391 }
392
393 src.is_coercible_to(target)
394 }
395 (Self::Compound(src, src_opt), Self::Compound(target, target_opt)) => {
396 if *src_opt && !*target_opt {
398 return false;
399 }
400
401 src.is_coercible_to(target)
402 }
403
404 (Self::Object, Self::Object)
406 | (Self::Object, Self::OptionalObject)
407 | (Self::OptionalObject, Self::OptionalObject) => true,
408
409 (Self::Compound(src, false), Self::Object)
412 | (Self::Compound(src, false), Self::OptionalObject)
413 | (Self::Compound(src, _), Self::OptionalObject) => match src {
414 CompoundType::Map(src) => {
415 matches!(src.key_type, Type::Primitive(PrimitiveType::String, _))
416 }
417 CompoundType::Struct(_) => true,
418 _ => false,
419 },
420
421 (Self::Object, Self::Compound(target, _))
426 | (Self::OptionalObject, Self::Compound(target, true)) => {
427 match target {
428 CompoundType::Map(target) => {
429 matches!(target.key_type, Type::Primitive(PrimitiveType::String, _))
430 }
431 CompoundType::Struct(_) => {
432 true
434 }
435 _ => false,
436 }
437 }
438
439 (Self::Union, _) | (_, Self::Union) => true,
441
442 (Self::None, ty) if ty.is_optional() => true,
444
445 _ => false,
447 }
448 }
449}
450
451impl From<PrimitiveType> for Type {
452 fn from(value: PrimitiveType) -> Self {
453 Self::Primitive(value, false)
454 }
455}
456
457impl From<CompoundType> for Type {
458 fn from(value: CompoundType) -> Self {
459 Self::Compound(value, false)
460 }
461}
462
463impl From<ArrayType> for Type {
464 fn from(value: ArrayType) -> Self {
465 Self::Compound(value.into(), false)
466 }
467}
468
469impl From<PairType> for Type {
470 fn from(value: PairType) -> Self {
471 Self::Compound(value.into(), false)
472 }
473}
474
475impl From<MapType> for Type {
476 fn from(value: MapType) -> Self {
477 Self::Compound(value.into(), false)
478 }
479}
480
481impl From<StructType> for Type {
482 fn from(value: StructType) -> Self {
483 Self::Compound(value.into(), false)
484 }
485}
486
487impl From<CallType> for Type {
488 fn from(value: CallType) -> Self {
489 Self::Call(value)
490 }
491}
492
493#[derive(Debug, Clone, PartialEq, Eq)]
495pub enum CompoundType {
496 Array(ArrayType),
498 Pair(Arc<PairType>),
500 Map(Arc<MapType>),
502 Struct(Arc<StructType>),
504}
505
506impl CompoundType {
507 pub fn as_array(&self) -> Option<&ArrayType> {
511 match self {
512 Self::Array(ty) => Some(ty),
513 _ => None,
514 }
515 }
516
517 pub fn as_pair(&self) -> Option<&PairType> {
521 match self {
522 Self::Pair(ty) => Some(ty),
523 _ => None,
524 }
525 }
526
527 pub fn as_map(&self) -> Option<&MapType> {
531 match self {
532 Self::Map(ty) => Some(ty),
533 _ => None,
534 }
535 }
536
537 pub fn as_struct(&self) -> Option<&StructType> {
541 match self {
542 Self::Struct(ty) => Some(ty),
543 _ => None,
544 }
545 }
546
547 fn common_type(&self, other: &Self) -> Option<CompoundType> {
552 match (self, other) {
555 (Self::Array(this), Self::Array(other)) => {
556 let element_type = this.element_type.common_type(&other.element_type)?;
557 Some(ArrayType::new(element_type).into())
558 }
559 (Self::Pair(this), Self::Pair(other)) => {
560 let left_type = this.left_type.common_type(&other.left_type)?;
561 let right_type = this.right_type.common_type(&other.right_type)?;
562 Some(PairType::new(left_type, right_type).into())
563 }
564 (Self::Map(this), Self::Map(other)) => {
565 let key_type = this.key_type.common_type(&other.key_type)?;
566 let value_type = this.value_type.common_type(&other.value_type)?;
567 Some(MapType::new(key_type, value_type).into())
568 }
569 _ => None,
570 }
571 }
572}
573
574impl fmt::Display for CompoundType {
575 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576 match self {
577 Self::Array(ty) => ty.fmt(f),
578 Self::Pair(ty) => ty.fmt(f),
579 Self::Map(ty) => ty.fmt(f),
580 Self::Struct(ty) => ty.fmt(f),
581 }
582 }
583}
584
585impl Coercible for CompoundType {
586 fn is_coercible_to(&self, target: &Self) -> bool {
587 match (self, target) {
588 (Self::Array(src), Self::Array(target)) => src.is_coercible_to(target),
591
592 (Self::Pair(src), Self::Pair(target)) => src.is_coercible_to(target),
595
596 (Self::Map(src), Self::Map(target)) => src.is_coercible_to(target),
599
600 (Self::Struct(src), Self::Struct(target)) => src.is_coercible_to(target),
603
604 (Self::Map(src), Self::Struct(target)) => {
607 if !matches!(src.key_type, Type::Primitive(PrimitiveType::String, _)) {
608 return false;
609 }
610
611 if !target
613 .members
614 .values()
615 .all(|ty| src.value_type.is_coercible_to(ty))
616 {
617 return false;
618 }
619
620 true
622 }
623
624 (Self::Struct(src), Self::Map(target)) => {
627 if !matches!(target.key_type, Type::Primitive(PrimitiveType::String, _)) {
628 return false;
629 }
630
631 if !src
633 .members
634 .values()
635 .all(|ty| ty.is_coercible_to(&target.value_type))
636 {
637 return false;
638 }
639
640 true
641 }
642
643 _ => false,
644 }
645 }
646}
647
648impl From<ArrayType> for CompoundType {
649 fn from(value: ArrayType) -> Self {
650 Self::Array(value)
651 }
652}
653
654impl From<PairType> for CompoundType {
655 fn from(value: PairType) -> Self {
656 Self::Pair(value.into())
657 }
658}
659
660impl From<MapType> for CompoundType {
661 fn from(value: MapType) -> Self {
662 Self::Map(value.into())
663 }
664}
665
666impl From<StructType> for CompoundType {
667 fn from(value: StructType) -> Self {
668 Self::Struct(value.into())
669 }
670}
671
672#[derive(Debug, Clone, PartialEq, Eq)]
674pub struct ArrayType {
675 element_type: Arc<Type>,
677 non_empty: bool,
679}
680
681impl ArrayType {
682 pub fn new(element_type: impl Into<Type>) -> Self {
684 Self {
685 element_type: Arc::new(element_type.into()),
686 non_empty: false,
687 }
688 }
689
690 pub fn non_empty(element_type: impl Into<Type>) -> Self {
692 Self {
693 element_type: Arc::new(element_type.into()),
694 non_empty: true,
695 }
696 }
697
698 pub fn element_type(&self) -> &Type {
700 &self.element_type
701 }
702
703 pub fn is_non_empty(&self) -> bool {
705 self.non_empty
706 }
707
708 pub fn unqualified(self) -> ArrayType {
710 Self {
711 element_type: self.element_type,
712 non_empty: false,
713 }
714 }
715}
716
717impl fmt::Display for ArrayType {
718 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719 write!(f, "Array[{ty}]", ty = self.element_type)?;
720
721 if self.non_empty {
722 write!(f, "+")?;
723 }
724
725 Ok(())
726 }
727}
728
729impl Coercible for ArrayType {
730 fn is_coercible_to(&self, target: &Self) -> bool {
731 self.element_type.is_coercible_to(&target.element_type)
733 }
734}
735
736#[derive(Debug, Clone, PartialEq, Eq)]
738pub struct PairType {
739 left_type: Type,
741 right_type: Type,
743}
744
745impl PairType {
746 pub fn new(left_type: impl Into<Type>, right_type: impl Into<Type>) -> Self {
748 Self {
749 left_type: left_type.into(),
750 right_type: right_type.into(),
751 }
752 }
753
754 pub fn left_type(&self) -> &Type {
756 &self.left_type
757 }
758
759 pub fn right_type(&self) -> &Type {
761 &self.right_type
762 }
763}
764
765impl fmt::Display for PairType {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 write!(
768 f,
769 "Pair[{left}, {right}]",
770 left = self.left_type,
771 right = self.right_type
772 )?;
773
774 Ok(())
775 }
776}
777
778impl Coercible for PairType {
779 fn is_coercible_to(&self, target: &Self) -> bool {
780 self.left_type.is_coercible_to(&target.left_type)
781 && self.right_type.is_coercible_to(&target.right_type)
782 }
783}
784
785#[derive(Debug, Clone, PartialEq, Eq)]
787pub struct MapType {
788 key_type: Type,
790 value_type: Type,
792}
793
794impl MapType {
795 pub fn new(key_type: impl Into<Type>, value_type: impl Into<Type>) -> Self {
797 Self {
798 key_type: key_type.into(),
799 value_type: value_type.into(),
800 }
801 }
802
803 pub fn key_type(&self) -> &Type {
805 &self.key_type
806 }
807
808 pub fn value_type(&self) -> &Type {
810 &self.value_type
811 }
812}
813
814impl fmt::Display for MapType {
815 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
816 write!(
817 f,
818 "Map[{key}, {value}]",
819 key = self.key_type,
820 value = self.value_type
821 )?;
822
823 Ok(())
824 }
825}
826
827impl Coercible for MapType {
828 fn is_coercible_to(&self, target: &Self) -> bool {
829 self.key_type.is_coercible_to(&target.key_type)
830 && self.value_type.is_coercible_to(&target.value_type)
831 }
832}
833
834#[derive(Debug, PartialEq, Eq)]
836pub struct StructType {
837 name: Arc<String>,
839 members: IndexMap<String, Type>,
841}
842
843impl StructType {
844 pub fn new<N, T>(name: impl Into<String>, members: impl IntoIterator<Item = (N, T)>) -> Self
846 where
847 N: Into<String>,
848 T: Into<Type>,
849 {
850 Self {
851 name: Arc::new(name.into()),
852 members: members
853 .into_iter()
854 .map(|(n, ty)| (n.into(), ty.into()))
855 .collect(),
856 }
857 }
858
859 pub fn name(&self) -> &Arc<String> {
861 &self.name
862 }
863
864 pub fn members(&self) -> &IndexMap<String, Type> {
866 &self.members
867 }
868}
869
870impl fmt::Display for StructType {
871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 write!(f, "{name}", name = self.name)
873 }
874}
875
876impl Coercible for StructType {
877 fn is_coercible_to(&self, target: &Self) -> bool {
878 if self.members.len() != target.members.len() {
879 return false;
880 }
881
882 self.members.iter().all(|(k, v)| {
883 target
884 .members
885 .get(k)
886 .map(|target| v.is_coercible_to(target))
887 .unwrap_or(false)
888 })
889 }
890}
891
892#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
894pub enum CallKind {
895 Task,
897 Workflow,
899}
900
901impl fmt::Display for CallKind {
902 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
903 match self {
904 Self::Task => write!(f, "task"),
905 Self::Workflow => write!(f, "workflow"),
906 }
907 }
908}
909
910#[derive(Debug, Clone, Eq)]
912pub struct CallType {
913 kind: CallKind,
915 namespace: Option<Arc<String>>,
917 name: Arc<String>,
919 specified: Arc<HashSet<String>>,
921 inputs: Arc<IndexMap<String, Input>>,
923 outputs: Arc<IndexMap<String, Output>>,
925}
926
927impl CallType {
928 pub fn new(
930 kind: CallKind,
931 name: impl Into<String>,
932 specified: Arc<HashSet<String>>,
933 inputs: Arc<IndexMap<String, Input>>,
934 outputs: Arc<IndexMap<String, Output>>,
935 ) -> Self {
936 Self {
937 kind,
938 namespace: None,
939 name: Arc::new(name.into()),
940 specified,
941 inputs,
942 outputs,
943 }
944 }
945
946 pub fn namespaced(
949 kind: CallKind,
950 namespace: impl Into<String>,
951 name: impl Into<String>,
952 specified: Arc<HashSet<String>>,
953 inputs: Arc<IndexMap<String, Input>>,
954 outputs: Arc<IndexMap<String, Output>>,
955 ) -> Self {
956 Self {
957 kind,
958 namespace: Some(Arc::new(namespace.into())),
959 name: Arc::new(name.into()),
960 specified,
961 inputs,
962 outputs,
963 }
964 }
965
966 pub fn kind(&self) -> CallKind {
968 self.kind
969 }
970
971 pub fn namespace(&self) -> Option<&str> {
975 self.namespace.as_ref().map(|ns| ns.as_str())
976 }
977
978 pub fn name(&self) -> &str {
980 &self.name
981 }
982
983 pub fn specified(&self) -> &HashSet<String> {
985 &self.specified
986 }
987
988 pub fn inputs(&self) -> &IndexMap<String, Input> {
990 &self.inputs
991 }
992
993 pub fn outputs(&self) -> &IndexMap<String, Output> {
995 &self.outputs
996 }
997
998 pub fn promote(&self, kind: PromotionKind) -> Self {
1000 let mut ty = self.clone();
1001 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
1002 *output = Output::new(output.ty().promote(kind), output.name_span());
1003 }
1004
1005 ty
1006 }
1007}
1008
1009impl Coercible for CallType {
1010 fn is_coercible_to(&self, _: &Self) -> bool {
1011 false
1013 }
1014}
1015
1016impl fmt::Display for CallType {
1017 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1018 if let Some(ns) = &self.namespace {
1019 write!(
1020 f,
1021 "call to {kind} `{ns}.{name}`",
1022 kind = self.kind,
1023 name = self.name,
1024 )
1025 } else {
1026 write!(
1027 f,
1028 "call to {kind} `{name}`",
1029 kind = self.kind,
1030 name = self.name,
1031 )
1032 }
1033 }
1034}
1035
1036impl PartialEq for CallType {
1037 fn eq(&self, other: &Self) -> bool {
1038 std::ptr::eq(self, other)
1040 }
1041}
1042
1043#[cfg(test)]
1044mod test {
1045 use pretty_assertions::assert_eq;
1046
1047 use super::*;
1048
1049 #[test]
1050 fn primitive_type_display() {
1051 assert_eq!(PrimitiveType::Boolean.to_string(), "Boolean");
1052 assert_eq!(PrimitiveType::Integer.to_string(), "Int");
1053 assert_eq!(PrimitiveType::Float.to_string(), "Float");
1054 assert_eq!(PrimitiveType::String.to_string(), "String");
1055 assert_eq!(PrimitiveType::File.to_string(), "File");
1056 assert_eq!(PrimitiveType::Directory.to_string(), "Directory");
1057 assert_eq!(
1058 Type::from(PrimitiveType::Boolean).optional().to_string(),
1059 "Boolean?"
1060 );
1061 assert_eq!(
1062 Type::from(PrimitiveType::Integer).optional().to_string(),
1063 "Int?"
1064 );
1065 assert_eq!(
1066 Type::from(PrimitiveType::Float).optional().to_string(),
1067 "Float?"
1068 );
1069 assert_eq!(
1070 Type::from(PrimitiveType::String).optional().to_string(),
1071 "String?"
1072 );
1073 assert_eq!(
1074 Type::from(PrimitiveType::File).optional().to_string(),
1075 "File?"
1076 );
1077 assert_eq!(
1078 Type::from(PrimitiveType::Directory).optional().to_string(),
1079 "Directory?"
1080 );
1081 }
1082
1083 #[test]
1084 fn array_type_display() {
1085 assert_eq!(
1086 ArrayType::new(PrimitiveType::String).to_string(),
1087 "Array[String]"
1088 );
1089 assert_eq!(
1090 ArrayType::non_empty(PrimitiveType::String).to_string(),
1091 "Array[String]+"
1092 );
1093
1094 let ty: Type = ArrayType::new(ArrayType::new(PrimitiveType::String)).into();
1095 assert_eq!(ty.to_string(), "Array[Array[String]]");
1096
1097 let ty = Type::from(ArrayType::non_empty(
1098 Type::from(ArrayType::non_empty(
1099 Type::from(PrimitiveType::String).optional(),
1100 ))
1101 .optional(),
1102 ))
1103 .optional();
1104 assert_eq!(ty.to_string(), "Array[Array[String?]+?]+?");
1105 }
1106
1107 #[test]
1108 fn pair_type_display() {
1109 assert_eq!(
1110 PairType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1111 "Pair[String, Boolean]"
1112 );
1113
1114 let ty: Type = PairType::new(
1115 ArrayType::new(PrimitiveType::String),
1116 ArrayType::new(PrimitiveType::String),
1117 )
1118 .into();
1119 assert_eq!(ty.to_string(), "Pair[Array[String], Array[String]]");
1120
1121 let ty = Type::from(PairType::new(
1122 Type::from(ArrayType::non_empty(
1123 Type::from(PrimitiveType::File).optional(),
1124 ))
1125 .optional(),
1126 Type::from(ArrayType::non_empty(
1127 Type::from(PrimitiveType::File).optional(),
1128 ))
1129 .optional(),
1130 ))
1131 .optional();
1132 assert_eq!(ty.to_string(), "Pair[Array[File?]+?, Array[File?]+?]?");
1133 }
1134
1135 #[test]
1136 fn map_type_display() {
1137 assert_eq!(
1138 MapType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1139 "Map[String, Boolean]"
1140 );
1141
1142 let ty: Type = MapType::new(
1143 PrimitiveType::Boolean,
1144 ArrayType::new(PrimitiveType::String),
1145 )
1146 .into();
1147 assert_eq!(ty.to_string(), "Map[Boolean, Array[String]]");
1148
1149 let ty: Type = Type::from(MapType::new(
1150 PrimitiveType::String,
1151 Type::from(ArrayType::non_empty(
1152 Type::from(PrimitiveType::File).optional(),
1153 ))
1154 .optional(),
1155 ))
1156 .optional();
1157 assert_eq!(ty.to_string(), "Map[String, Array[File?]+?]?");
1158 }
1159
1160 #[test]
1161 fn struct_type_display() {
1162 assert_eq!(
1163 StructType::new("Foobar", std::iter::empty::<(String, Type)>()).to_string(),
1164 "Foobar"
1165 );
1166 }
1167
1168 #[test]
1169 fn object_type_display() {
1170 assert_eq!(Type::Object.to_string(), "Object");
1171 assert_eq!(Type::OptionalObject.to_string(), "Object?");
1172 }
1173
1174 #[test]
1175 fn union_type_display() {
1176 assert_eq!(Type::Union.to_string(), "Union");
1177 }
1178
1179 #[test]
1180 fn none_type_display() {
1181 assert_eq!(Type::None.to_string(), "None");
1182 }
1183
1184 #[test]
1185 fn primitive_type_coercion() {
1186 for ty in [
1189 Type::from(PrimitiveType::Boolean),
1190 PrimitiveType::Directory.into(),
1191 PrimitiveType::File.into(),
1192 PrimitiveType::Float.into(),
1193 PrimitiveType::Integer.into(),
1194 PrimitiveType::String.into(),
1195 ] {
1196 assert!(ty.is_coercible_to(&ty));
1197 assert!(ty.optional().is_coercible_to(&ty.optional()));
1198 assert!(ty.is_coercible_to(&ty.optional()));
1199 assert!(!ty.optional().is_coercible_to(&ty));
1200 }
1201
1202 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::File));
1204 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::Directory));
1205 assert!(PrimitiveType::Integer.is_coercible_to(&PrimitiveType::Float));
1206 assert!(PrimitiveType::File.is_coercible_to(&PrimitiveType::String));
1207 assert!(PrimitiveType::Directory.is_coercible_to(&PrimitiveType::String));
1208 assert!(!PrimitiveType::Float.is_coercible_to(&PrimitiveType::Integer));
1209 }
1210
1211 #[test]
1212 fn object_type_coercion() {
1213 assert!(Type::Object.is_coercible_to(&Type::Object));
1214 assert!(Type::Object.is_coercible_to(&Type::OptionalObject));
1215 assert!(Type::OptionalObject.is_coercible_to(&Type::OptionalObject));
1216 assert!(!Type::OptionalObject.is_coercible_to(&Type::Object));
1217
1218 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1220 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1221
1222 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1224 assert!(!Type::Object.is_coercible_to(&ty));
1225
1226 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1228 assert!(Type::Object.is_coercible_to(&ty));
1229
1230 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1232 assert!(Type::OptionalObject.is_coercible_to(&ty));
1233
1234 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1236 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1237
1238 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1240 assert!(Type::Object.is_coercible_to(&ty));
1241
1242 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1244 assert!(Type::Object.is_coercible_to(&ty));
1245
1246 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1248 assert!(Type::OptionalObject.is_coercible_to(&ty));
1249
1250 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1252 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1253 }
1254
1255 #[test]
1256 fn array_type_coercion() {
1257 assert!(
1259 ArrayType::new(PrimitiveType::String)
1260 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1261 );
1262 assert!(
1263 ArrayType::new(PrimitiveType::File)
1264 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1265 );
1266 assert!(
1267 ArrayType::new(PrimitiveType::String)
1268 .is_coercible_to(&ArrayType::new(PrimitiveType::File))
1269 );
1270
1271 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1273 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1274 assert!(type1.is_coercible_to(&type2));
1275 assert!(!type2.is_coercible_to(&type1));
1276
1277 let type1: Type = ArrayType::new(type1).into();
1279 let type2 = ArrayType::new(type2).into();
1280 assert!(type1.is_coercible_to(&type2));
1281 assert!(!type2.is_coercible_to(&type1));
1282
1283 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1285 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1286 assert!(type1.is_coercible_to(&type2));
1287 assert!(!type2.is_coercible_to(&type1));
1288
1289 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1291 let type2 = ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
1292 assert!(type1.is_coercible_to(&type2));
1293 assert!(!type2.is_coercible_to(&type1));
1294
1295 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1297 let type2 = ArrayType::new(PrimitiveType::String).into();
1298 assert!(type1.is_coercible_to(&type2));
1299 assert!(type2.is_coercible_to(&type1));
1300
1301 let type1 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1303 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1304 assert!(type1.is_coercible_to(&type2));
1305 assert!(type2.is_coercible_to(&type1));
1306
1307 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1309 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1310 assert!(type1.is_coercible_to(&type2));
1311 assert!(!type2.is_coercible_to(&type1));
1312 }
1313
1314 #[test]
1315 fn pair_type_coercion() {
1316 assert!(
1318 PairType::new(PrimitiveType::String, PrimitiveType::String)
1319 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1320 );
1321 assert!(
1322 PairType::new(PrimitiveType::String, PrimitiveType::String).is_coercible_to(
1323 &PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1324 )
1325 );
1326 assert!(
1327 PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1328 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1329 );
1330
1331 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1333 let type2 = PairType::new(
1334 Type::from(PrimitiveType::File).optional(),
1335 Type::from(PrimitiveType::Directory).optional(),
1336 )
1337 .into();
1338 assert!(type1.is_coercible_to(&type2));
1339 assert!(!type2.is_coercible_to(&type1));
1340
1341 let type1: Type = PairType::new(type1.clone(), type1).into();
1343 let type2 = PairType::new(type2.clone(), type2).into();
1344 assert!(type1.is_coercible_to(&type2));
1345 assert!(!type2.is_coercible_to(&type1));
1346
1347 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1349 let type2 = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1350 assert!(type1.is_coercible_to(&type2));
1351 assert!(type2.is_coercible_to(&type1));
1352
1353 let type1 =
1355 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1356 let type2 =
1357 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1358 assert!(type1.is_coercible_to(&type2));
1359 assert!(type2.is_coercible_to(&type1));
1360
1361 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1363 let type2 =
1364 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1365 assert!(type1.is_coercible_to(&type2));
1366 assert!(!type2.is_coercible_to(&type1));
1367 }
1368
1369 #[test]
1370 fn map_type_coercion() {
1371 assert!(
1373 MapType::new(PrimitiveType::String, PrimitiveType::String)
1374 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1375 );
1376 assert!(
1377 MapType::new(PrimitiveType::String, PrimitiveType::String)
1378 .is_coercible_to(&MapType::new(PrimitiveType::File, PrimitiveType::Directory))
1379 );
1380 assert!(
1381 MapType::new(PrimitiveType::File, PrimitiveType::Directory)
1382 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1383 );
1384
1385 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1387 let type2 = MapType::new(
1388 Type::from(PrimitiveType::File).optional(),
1389 Type::from(PrimitiveType::Directory).optional(),
1390 )
1391 .into();
1392 assert!(type1.is_coercible_to(&type2));
1393 assert!(!type2.is_coercible_to(&type1));
1394
1395 let type1: Type = MapType::new(PrimitiveType::String, type1).into();
1397 let type2 = MapType::new(PrimitiveType::Directory, type2).into();
1398 assert!(type1.is_coercible_to(&type2));
1399 assert!(!type2.is_coercible_to(&type1));
1400
1401 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1403 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1404 assert!(type1.is_coercible_to(&type2));
1405 assert!(type2.is_coercible_to(&type1));
1406
1407 let type1: Type =
1409 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1410 let type2: Type =
1411 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1412 assert!(type1.is_coercible_to(&type2));
1413 assert!(type2.is_coercible_to(&type1));
1414
1415 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1417 let type2 =
1418 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1419 assert!(type1.is_coercible_to(&type2));
1420 assert!(!type2.is_coercible_to(&type1));
1421
1422 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1424 let type2 = StructType::new(
1425 "Foo",
1426 [
1427 ("foo", PrimitiveType::Integer),
1428 ("bar", PrimitiveType::Integer),
1429 ("baz", PrimitiveType::Integer),
1430 ],
1431 )
1432 .into();
1433 assert!(type1.is_coercible_to(&type2));
1434
1435 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1437 let type2 = StructType::new(
1438 "Foo",
1439 [
1440 ("foo", PrimitiveType::Integer),
1441 ("bar", PrimitiveType::String),
1442 ("baz", PrimitiveType::Integer),
1443 ],
1444 )
1445 .into();
1446 assert!(!type1.is_coercible_to(&type2));
1447
1448 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1450 let type2 = StructType::new(
1451 "Foo",
1452 [
1453 ("foo", PrimitiveType::Integer),
1454 ("bar", PrimitiveType::Integer),
1455 ("baz", PrimitiveType::Integer),
1456 ],
1457 )
1458 .into();
1459 assert!(!type1.is_coercible_to(&type2));
1460
1461 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1463 assert!(type1.is_coercible_to(&Type::Object));
1464
1465 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1467 assert!(type1.is_coercible_to(&Type::OptionalObject));
1468
1469 let type1: Type =
1471 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1472 assert!(type1.is_coercible_to(&Type::OptionalObject));
1473
1474 let type1: Type =
1476 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1477 assert!(!type1.is_coercible_to(&Type::Object));
1478
1479 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1481 assert!(!type1.is_coercible_to(&Type::Object));
1482 }
1483
1484 #[test]
1485 fn struct_type_coercion() {
1486 let type1: Type = StructType::new(
1488 "Foo",
1489 [
1490 ("foo", PrimitiveType::String),
1491 ("bar", PrimitiveType::String),
1492 ("baz", PrimitiveType::Integer),
1493 ],
1494 )
1495 .into();
1496 let type2 = StructType::new(
1497 "Foo",
1498 [
1499 ("foo", PrimitiveType::String),
1500 ("bar", PrimitiveType::String),
1501 ("baz", PrimitiveType::Integer),
1502 ],
1503 )
1504 .into();
1505 assert!(type1.is_coercible_to(&type2));
1506 assert!(type2.is_coercible_to(&type1));
1507
1508 let type1: Type = StructType::new(
1510 "Foo",
1511 [
1512 ("foo", PrimitiveType::String),
1513 ("bar", PrimitiveType::String),
1514 ("baz", PrimitiveType::Integer),
1515 ],
1516 )
1517 .into();
1518 let type2 = Type::from(StructType::new(
1519 "Foo",
1520 [
1521 ("foo", PrimitiveType::String),
1522 ("bar", PrimitiveType::String),
1523 ("baz", PrimitiveType::Integer),
1524 ],
1525 ))
1526 .optional();
1527 assert!(type1.is_coercible_to(&type2));
1528 assert!(!type2.is_coercible_to(&type1));
1529
1530 let type1: Type = Type::from(StructType::new(
1532 "Foo",
1533 [
1534 ("foo", PrimitiveType::String),
1535 ("bar", PrimitiveType::String),
1536 ("baz", PrimitiveType::Integer),
1537 ],
1538 ))
1539 .optional();
1540 let type2 = Type::from(StructType::new(
1541 "Foo",
1542 [
1543 ("foo", PrimitiveType::String),
1544 ("bar", PrimitiveType::String),
1545 ("baz", PrimitiveType::Integer),
1546 ],
1547 ))
1548 .optional();
1549 assert!(type1.is_coercible_to(&type2));
1550 assert!(type2.is_coercible_to(&type1));
1551
1552 let type1: Type = StructType::new(
1554 "Foo",
1555 [
1556 ("foo", PrimitiveType::String),
1557 ("bar", PrimitiveType::String),
1558 ("baz", PrimitiveType::Integer),
1559 ],
1560 )
1561 .into();
1562 let type2 = StructType::new(
1563 "Bar",
1564 [
1565 ("foo", PrimitiveType::File),
1566 ("bar", PrimitiveType::Directory),
1567 ("baz", PrimitiveType::Float),
1568 ],
1569 )
1570 .into();
1571 assert!(type1.is_coercible_to(&type2));
1572 assert!(!type2.is_coercible_to(&type1));
1573
1574 let type1: Type = StructType::new(
1576 "Foo",
1577 [
1578 ("foo", PrimitiveType::String),
1579 ("bar", PrimitiveType::String),
1580 ("baz", PrimitiveType::Integer),
1581 ],
1582 )
1583 .into();
1584 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1585 assert!(!type1.is_coercible_to(&type2));
1586 assert!(!type2.is_coercible_to(&type1));
1587
1588 let type1: Type = StructType::new(
1590 "Foo",
1591 [
1592 ("foo", PrimitiveType::String),
1593 ("bar", PrimitiveType::String),
1594 ("baz", PrimitiveType::String),
1595 ],
1596 )
1597 .into();
1598 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1599 assert!(type1.is_coercible_to(&type2));
1600
1601 let type1: Type = StructType::new(
1603 "Foo",
1604 [
1605 ("foo", PrimitiveType::String),
1606 ("bar", PrimitiveType::Integer),
1607 ("baz", PrimitiveType::String),
1608 ],
1609 )
1610 .into();
1611 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1612 assert!(!type1.is_coercible_to(&type2));
1613
1614 let type1: Type = StructType::new(
1616 "Foo",
1617 [
1618 ("foo", PrimitiveType::String),
1619 ("bar", PrimitiveType::String),
1620 ("baz", PrimitiveType::String),
1621 ],
1622 )
1623 .into();
1624 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1625 assert!(!type1.is_coercible_to(&type2));
1626
1627 assert!(type1.is_coercible_to(&Type::Object));
1629
1630 assert!(type1.is_coercible_to(&Type::OptionalObject));
1632
1633 let type1: Type =
1635 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1636 assert!(type1.is_coercible_to(&Type::OptionalObject));
1637
1638 assert!(!type1.is_coercible_to(&Type::Object));
1640 }
1641
1642 #[test]
1643 fn union_type_coercion() {
1644 for ty in [
1646 Type::from(PrimitiveType::Boolean),
1647 PrimitiveType::Directory.into(),
1648 PrimitiveType::File.into(),
1649 PrimitiveType::Float.into(),
1650 PrimitiveType::Integer.into(),
1651 PrimitiveType::String.into(),
1652 ] {
1653 assert!(Type::Union.is_coercible_to(&ty));
1654 assert!(Type::Union.is_coercible_to(&ty.optional()));
1655 assert!(ty.is_coercible_to(&Type::Union));
1656 }
1657
1658 for optional in [true, false] {
1659 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1661 let ty = if optional { ty.optional() } else { ty };
1662
1663 let coercible = Type::Union.is_coercible_to(&ty);
1664 assert!(coercible);
1665
1666 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1668 let ty = if optional { ty.optional() } else { ty };
1669 let coercible = Type::Union.is_coercible_to(&ty);
1670 assert!(coercible);
1671
1672 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1674 let ty = if optional { ty.optional() } else { ty };
1675 let coercible = Type::Union.is_coercible_to(&ty);
1676 assert!(coercible);
1677
1678 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1680 let ty = if optional { ty.optional() } else { ty };
1681 let coercible = Type::Union.is_coercible_to(&ty);
1682 assert!(coercible);
1683 }
1684 }
1685
1686 #[test]
1687 fn none_type_coercion() {
1688 for ty in [
1690 Type::from(PrimitiveType::Boolean),
1691 PrimitiveType::Directory.into(),
1692 PrimitiveType::File.into(),
1693 PrimitiveType::Float.into(),
1694 PrimitiveType::Integer.into(),
1695 PrimitiveType::String.into(),
1696 ] {
1697 assert!(!Type::None.is_coercible_to(&ty));
1698 assert!(Type::None.is_coercible_to(&ty.optional()));
1699 assert!(!ty.is_coercible_to(&Type::None));
1700 }
1701
1702 for optional in [true, false] {
1703 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1705 let ty = if optional { ty.optional() } else { ty };
1706 let coercible = Type::None.is_coercible_to(&ty);
1707 if optional {
1708 assert!(coercible);
1709 } else {
1710 assert!(!coercible);
1711 }
1712
1713 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1715 let ty = if optional { ty.optional() } else { ty };
1716 let coercible = Type::None.is_coercible_to(&ty);
1717 if optional {
1718 assert!(coercible);
1719 } else {
1720 assert!(!coercible);
1721 }
1722
1723 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1725 let ty = if optional { ty.optional() } else { ty };
1726 let coercible = Type::None.is_coercible_to(&ty);
1727 if optional {
1728 assert!(coercible);
1729 } else {
1730 assert!(!coercible);
1731 }
1732
1733 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1735 let ty = if optional { ty.optional() } else { ty };
1736 let coercible = Type::None.is_coercible_to(&ty);
1737 if optional {
1738 assert!(coercible);
1739 } else {
1740 assert!(!coercible);
1741 }
1742 }
1743 }
1744
1745 #[test]
1746 fn primitive_equality() {
1747 for ty in [
1748 Type::from(PrimitiveType::Boolean),
1749 PrimitiveType::Directory.into(),
1750 PrimitiveType::File.into(),
1751 PrimitiveType::Float.into(),
1752 PrimitiveType::Integer.into(),
1753 PrimitiveType::String.into(),
1754 ] {
1755 assert!(ty.eq(&ty));
1756 assert!(!ty.optional().eq(&ty));
1757 assert!(!ty.eq(&ty.optional()));
1758 assert!(ty.optional().eq(&ty.optional()));
1759 assert!(!ty.eq(&Type::Object));
1760 assert!(!ty.eq(&Type::OptionalObject));
1761 assert!(!ty.eq(&Type::Union));
1762 assert!(!ty.eq(&Type::None));
1763 }
1764 }
1765
1766 #[test]
1767 fn array_equality() {
1768 let a: Type = ArrayType::new(PrimitiveType::String).into();
1770 let b: Type = ArrayType::new(PrimitiveType::String).into();
1771 assert!(a.eq(&b));
1772 assert!(!a.optional().eq(&b));
1773 assert!(!a.eq(&b.optional()));
1774 assert!(a.optional().eq(&b.optional()));
1775
1776 let a: Type = ArrayType::new(a).into();
1778 let b: Type = ArrayType::new(b).into();
1779 assert!(a.eq(&b));
1780
1781 let a: Type = ArrayType::non_empty(a).into();
1783 let b: Type = ArrayType::non_empty(b).into();
1784 assert!(a.eq(&b));
1785
1786 let a: Type = ArrayType::new(PrimitiveType::String).into();
1788 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1789 assert!(!a.eq(&b));
1790
1791 let a: Type = ArrayType::new(PrimitiveType::String).into();
1793 let b: Type = ArrayType::new(PrimitiveType::Integer).into();
1794 assert!(!a.eq(&b));
1795
1796 assert!(!a.eq(&Type::Object));
1797 assert!(!a.eq(&Type::OptionalObject));
1798 assert!(!a.eq(&Type::Union));
1799 assert!(!a.eq(&Type::None));
1800 }
1801
1802 #[test]
1803 fn pair_equality() {
1804 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1806 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1807 assert!(a.eq(&b));
1808 assert!(!a.optional().eq(&b));
1809 assert!(!a.eq(&b.optional()));
1810 assert!(a.optional().eq(&b.optional()));
1811
1812 let a: Type = PairType::new(a.clone(), a).into();
1815 let b: Type = PairType::new(b.clone(), b).into();
1816 assert!(a.eq(&b));
1817
1818 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1820 let b: Type =
1821 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1822 assert!(!a.eq(&b));
1823
1824 assert!(!a.eq(&Type::Object));
1825 assert!(!a.eq(&Type::OptionalObject));
1826 assert!(!a.eq(&Type::Union));
1827 assert!(!a.eq(&Type::None));
1828 }
1829
1830 #[test]
1831 fn map_equality() {
1832 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1834 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1835 assert!(a.eq(&b));
1836 assert!(!a.optional().eq(&b));
1837 assert!(!a.eq(&b.optional()));
1838 assert!(a.optional().eq(&b.optional()));
1839
1840 let a: Type = MapType::new(PrimitiveType::File, a).into();
1842 let b = MapType::new(PrimitiveType::File, b).into();
1843 assert!(a.eq(&b));
1844
1845 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1847 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1848 assert!(!a.eq(&b));
1849
1850 assert!(!a.eq(&Type::Object));
1851 assert!(!a.eq(&Type::OptionalObject));
1852 assert!(!a.eq(&Type::Union));
1853 assert!(!a.eq(&Type::None));
1854 }
1855
1856 #[test]
1857 fn struct_equality() {
1858 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1859 assert!(a.eq(&a));
1860 assert!(!a.optional().eq(&a));
1861 assert!(!a.eq(&a.optional()));
1862 assert!(a.optional().eq(&a.optional()));
1863
1864 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1865 assert!(a.eq(&b));
1866 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1867 assert!(!a.eq(&b));
1868 }
1869
1870 #[test]
1871 fn object_equality() {
1872 assert!(Type::Object.eq(&Type::Object));
1873 assert!(!Type::OptionalObject.eq(&Type::Object));
1874 assert!(!Type::Object.eq(&Type::OptionalObject));
1875 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1876 }
1877
1878 #[test]
1879 fn union_equality() {
1880 assert!(Type::Union.eq(&Type::Union));
1881 assert!(!Type::None.eq(&Type::Union));
1882 assert!(!Type::Union.eq(&Type::None));
1883 assert!(Type::None.eq(&Type::None));
1884 }
1885}