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 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(
1409 "Foo",
1410 [
1411 ("foo", PrimitiveType::Integer),
1412 ("bar", PrimitiveType::Integer),
1413 ("baz", PrimitiveType::Integer),
1414 ],
1415 )
1416 .into();
1417 assert!(type1.is_coercible_to(&type2));
1418
1419 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1421 let type2 = StructType::new(
1422 "Foo",
1423 [
1424 ("foo", PrimitiveType::Integer),
1425 ("bar", PrimitiveType::String),
1426 ("baz", PrimitiveType::Integer),
1427 ],
1428 )
1429 .into();
1430 assert!(!type1.is_coercible_to(&type2));
1431
1432 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1434 let type2 = StructType::new(
1435 "Foo",
1436 [
1437 ("foo", PrimitiveType::Integer),
1438 ("bar", PrimitiveType::Integer),
1439 ("baz", PrimitiveType::Integer),
1440 ],
1441 )
1442 .into();
1443 assert!(!type1.is_coercible_to(&type2));
1444
1445 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1447 assert!(type1.is_coercible_to(&Type::Object));
1448
1449 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1451 assert!(type1.is_coercible_to(&Type::OptionalObject));
1452
1453 let type1: Type =
1455 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1456 assert!(type1.is_coercible_to(&Type::OptionalObject));
1457
1458 let type1: Type =
1460 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1461 assert!(!type1.is_coercible_to(&Type::Object));
1462
1463 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1465 assert!(!type1.is_coercible_to(&Type::Object));
1466 }
1467
1468 #[test]
1469 fn struct_type_coercion() {
1470 let type1: Type = StructType::new(
1472 "Foo",
1473 [
1474 ("foo", PrimitiveType::String),
1475 ("bar", PrimitiveType::String),
1476 ("baz", PrimitiveType::Integer),
1477 ],
1478 )
1479 .into();
1480 let type2 = StructType::new(
1481 "Foo",
1482 [
1483 ("foo", PrimitiveType::String),
1484 ("bar", PrimitiveType::String),
1485 ("baz", PrimitiveType::Integer),
1486 ],
1487 )
1488 .into();
1489 assert!(type1.is_coercible_to(&type2));
1490 assert!(type2.is_coercible_to(&type1));
1491
1492 let type1: Type = StructType::new(
1494 "Foo",
1495 [
1496 ("foo", PrimitiveType::String),
1497 ("bar", PrimitiveType::String),
1498 ("baz", PrimitiveType::Integer),
1499 ],
1500 )
1501 .into();
1502 let type2 = Type::from(StructType::new(
1503 "Foo",
1504 [
1505 ("foo", PrimitiveType::String),
1506 ("bar", PrimitiveType::String),
1507 ("baz", PrimitiveType::Integer),
1508 ],
1509 ))
1510 .optional();
1511 assert!(type1.is_coercible_to(&type2));
1512 assert!(!type2.is_coercible_to(&type1));
1513
1514 let type1: Type = Type::from(StructType::new(
1516 "Foo",
1517 [
1518 ("foo", PrimitiveType::String),
1519 ("bar", PrimitiveType::String),
1520 ("baz", PrimitiveType::Integer),
1521 ],
1522 ))
1523 .optional();
1524 let type2 = Type::from(StructType::new(
1525 "Foo",
1526 [
1527 ("foo", PrimitiveType::String),
1528 ("bar", PrimitiveType::String),
1529 ("baz", PrimitiveType::Integer),
1530 ],
1531 ))
1532 .optional();
1533 assert!(type1.is_coercible_to(&type2));
1534 assert!(type2.is_coercible_to(&type1));
1535
1536 let type1: Type = StructType::new(
1538 "Foo",
1539 [
1540 ("foo", PrimitiveType::String),
1541 ("bar", PrimitiveType::String),
1542 ("baz", PrimitiveType::Integer),
1543 ],
1544 )
1545 .into();
1546 let type2 = StructType::new(
1547 "Bar",
1548 [
1549 ("foo", PrimitiveType::File),
1550 ("bar", PrimitiveType::Directory),
1551 ("baz", PrimitiveType::Float),
1552 ],
1553 )
1554 .into();
1555 assert!(type1.is_coercible_to(&type2));
1556 assert!(!type2.is_coercible_to(&type1));
1557
1558 let type1: Type = StructType::new(
1560 "Foo",
1561 [
1562 ("foo", PrimitiveType::String),
1563 ("bar", PrimitiveType::String),
1564 ("baz", PrimitiveType::Integer),
1565 ],
1566 )
1567 .into();
1568 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1569 assert!(!type1.is_coercible_to(&type2));
1570 assert!(!type2.is_coercible_to(&type1));
1571
1572 let type1: Type = StructType::new(
1574 "Foo",
1575 [
1576 ("foo", PrimitiveType::String),
1577 ("bar", PrimitiveType::String),
1578 ("baz", PrimitiveType::String),
1579 ],
1580 )
1581 .into();
1582 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1583 assert!(type1.is_coercible_to(&type2));
1584
1585 let type1: Type = StructType::new(
1587 "Foo",
1588 [
1589 ("foo", PrimitiveType::String),
1590 ("bar", PrimitiveType::Integer),
1591 ("baz", PrimitiveType::String),
1592 ],
1593 )
1594 .into();
1595 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1596 assert!(!type1.is_coercible_to(&type2));
1597
1598 let type1: Type = StructType::new(
1600 "Foo",
1601 [
1602 ("foo", PrimitiveType::String),
1603 ("bar", PrimitiveType::String),
1604 ("baz", PrimitiveType::String),
1605 ],
1606 )
1607 .into();
1608 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1609 assert!(!type1.is_coercible_to(&type2));
1610
1611 assert!(type1.is_coercible_to(&Type::Object));
1613
1614 assert!(type1.is_coercible_to(&Type::OptionalObject));
1616
1617 let type1: Type =
1619 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1620 assert!(type1.is_coercible_to(&Type::OptionalObject));
1621
1622 assert!(!type1.is_coercible_to(&Type::Object));
1624 }
1625
1626 #[test]
1627 fn union_type_coercion() {
1628 for ty in [
1630 Type::from(PrimitiveType::Boolean),
1631 PrimitiveType::Directory.into(),
1632 PrimitiveType::File.into(),
1633 PrimitiveType::Float.into(),
1634 PrimitiveType::Integer.into(),
1635 PrimitiveType::String.into(),
1636 ] {
1637 assert!(Type::Union.is_coercible_to(&ty));
1638 assert!(Type::Union.is_coercible_to(&ty.optional()));
1639 assert!(ty.is_coercible_to(&Type::Union));
1640 }
1641
1642 for optional in [true, false] {
1643 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1645 let ty = if optional { ty.optional() } else { ty };
1646
1647 let coercible = Type::Union.is_coercible_to(&ty);
1648 assert!(coercible);
1649
1650 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1652 let ty = if optional { ty.optional() } else { ty };
1653 let coercible = Type::Union.is_coercible_to(&ty);
1654 assert!(coercible);
1655
1656 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1658 let ty = if optional { ty.optional() } else { ty };
1659 let coercible = Type::Union.is_coercible_to(&ty);
1660 assert!(coercible);
1661
1662 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1664 let ty = if optional { ty.optional() } else { ty };
1665 let coercible = Type::Union.is_coercible_to(&ty);
1666 assert!(coercible);
1667 }
1668 }
1669
1670 #[test]
1671 fn none_type_coercion() {
1672 for ty in [
1674 Type::from(PrimitiveType::Boolean),
1675 PrimitiveType::Directory.into(),
1676 PrimitiveType::File.into(),
1677 PrimitiveType::Float.into(),
1678 PrimitiveType::Integer.into(),
1679 PrimitiveType::String.into(),
1680 ] {
1681 assert!(!Type::None.is_coercible_to(&ty));
1682 assert!(Type::None.is_coercible_to(&ty.optional()));
1683 assert!(!ty.is_coercible_to(&Type::None));
1684 }
1685
1686 for optional in [true, false] {
1687 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1689 let ty = if optional { ty.optional() } else { ty };
1690 let coercible = Type::None.is_coercible_to(&ty);
1691 if optional {
1692 assert!(coercible);
1693 } else {
1694 assert!(!coercible);
1695 }
1696
1697 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1699 let ty = if optional { ty.optional() } else { ty };
1700 let coercible = Type::None.is_coercible_to(&ty);
1701 if optional {
1702 assert!(coercible);
1703 } else {
1704 assert!(!coercible);
1705 }
1706
1707 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1709 let ty = if optional { ty.optional() } else { ty };
1710 let coercible = Type::None.is_coercible_to(&ty);
1711 if optional {
1712 assert!(coercible);
1713 } else {
1714 assert!(!coercible);
1715 }
1716
1717 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1719 let ty = if optional { ty.optional() } else { ty };
1720 let coercible = Type::None.is_coercible_to(&ty);
1721 if optional {
1722 assert!(coercible);
1723 } else {
1724 assert!(!coercible);
1725 }
1726 }
1727 }
1728
1729 #[test]
1730 fn primitive_equality() {
1731 for ty in [
1732 Type::from(PrimitiveType::Boolean),
1733 PrimitiveType::Directory.into(),
1734 PrimitiveType::File.into(),
1735 PrimitiveType::Float.into(),
1736 PrimitiveType::Integer.into(),
1737 PrimitiveType::String.into(),
1738 ] {
1739 assert!(ty.eq(&ty));
1740 assert!(!ty.optional().eq(&ty));
1741 assert!(!ty.eq(&ty.optional()));
1742 assert!(ty.optional().eq(&ty.optional()));
1743 assert!(!ty.eq(&Type::Object));
1744 assert!(!ty.eq(&Type::OptionalObject));
1745 assert!(!ty.eq(&Type::Union));
1746 assert!(!ty.eq(&Type::None));
1747 }
1748 }
1749
1750 #[test]
1751 fn array_equality() {
1752 let a: Type = ArrayType::new(PrimitiveType::String).into();
1754 let b: Type = ArrayType::new(PrimitiveType::String).into();
1755 assert!(a.eq(&b));
1756 assert!(!a.optional().eq(&b));
1757 assert!(!a.eq(&b.optional()));
1758 assert!(a.optional().eq(&b.optional()));
1759
1760 let a: Type = ArrayType::new(a).into();
1762 let b: Type = ArrayType::new(b).into();
1763 assert!(a.eq(&b));
1764
1765 let a: Type = ArrayType::non_empty(a).into();
1767 let b: Type = ArrayType::non_empty(b).into();
1768 assert!(a.eq(&b));
1769
1770 let a: Type = ArrayType::new(PrimitiveType::String).into();
1772 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1773 assert!(!a.eq(&b));
1774
1775 let a: Type = ArrayType::new(PrimitiveType::String).into();
1777 let b: Type = ArrayType::new(PrimitiveType::Integer).into();
1778 assert!(!a.eq(&b));
1779
1780 assert!(!a.eq(&Type::Object));
1781 assert!(!a.eq(&Type::OptionalObject));
1782 assert!(!a.eq(&Type::Union));
1783 assert!(!a.eq(&Type::None));
1784 }
1785
1786 #[test]
1787 fn pair_equality() {
1788 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1790 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1791 assert!(a.eq(&b));
1792 assert!(!a.optional().eq(&b));
1793 assert!(!a.eq(&b.optional()));
1794 assert!(a.optional().eq(&b.optional()));
1795
1796 let a: Type = PairType::new(a.clone(), a).into();
1799 let b: Type = PairType::new(b.clone(), b).into();
1800 assert!(a.eq(&b));
1801
1802 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1804 let b: Type =
1805 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1806 assert!(!a.eq(&b));
1807
1808 assert!(!a.eq(&Type::Object));
1809 assert!(!a.eq(&Type::OptionalObject));
1810 assert!(!a.eq(&Type::Union));
1811 assert!(!a.eq(&Type::None));
1812 }
1813
1814 #[test]
1815 fn map_equality() {
1816 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1818 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1819 assert!(a.eq(&b));
1820 assert!(!a.optional().eq(&b));
1821 assert!(!a.eq(&b.optional()));
1822 assert!(a.optional().eq(&b.optional()));
1823
1824 let a: Type = MapType::new(PrimitiveType::File, a).into();
1826 let b = MapType::new(PrimitiveType::File, b).into();
1827 assert!(a.eq(&b));
1828
1829 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1831 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1832 assert!(!a.eq(&b));
1833
1834 assert!(!a.eq(&Type::Object));
1835 assert!(!a.eq(&Type::OptionalObject));
1836 assert!(!a.eq(&Type::Union));
1837 assert!(!a.eq(&Type::None));
1838 }
1839
1840 #[test]
1841 fn struct_equality() {
1842 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1843 assert!(a.eq(&a));
1844 assert!(!a.optional().eq(&a));
1845 assert!(!a.eq(&a.optional()));
1846 assert!(a.optional().eq(&a.optional()));
1847
1848 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1849 assert!(a.eq(&b));
1850 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1851 assert!(!a.eq(&b));
1852 }
1853
1854 #[test]
1855 fn object_equality() {
1856 assert!(Type::Object.eq(&Type::Object));
1857 assert!(!Type::OptionalObject.eq(&Type::Object));
1858 assert!(!Type::Object.eq(&Type::OptionalObject));
1859 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1860 }
1861
1862 #[test]
1863 fn union_equality() {
1864 assert!(Type::Union.eq(&Type::Union));
1865 assert!(!Type::None.eq(&Type::Union));
1866 assert!(!Type::Union.eq(&Type::None));
1867 assert!(Type::None.eq(&Type::None));
1868 }
1869}