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(Arc<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.into())
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: Type,
677 non_empty: bool,
682}
683
684impl ArrayType {
685 pub fn new(element_type: impl Into<Type>) -> Self {
687 Self {
688 element_type: element_type.into(),
689 non_empty: false,
690 }
691 }
692
693 pub fn non_empty(element_type: impl Into<Type>) -> Self {
695 Self {
696 element_type: element_type.into(),
697 non_empty: true,
698 }
699 }
700
701 pub fn element_type(&self) -> &Type {
703 &self.element_type
704 }
705
706 pub fn is_non_empty(&self) -> bool {
708 self.non_empty
709 }
710}
711
712impl fmt::Display for ArrayType {
713 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714 write!(f, "Array[{ty}]", ty = self.element_type)?;
715
716 if self.non_empty {
717 write!(f, "+")?;
718 }
719
720 Ok(())
721 }
722}
723
724impl Coercible for ArrayType {
725 fn is_coercible_to(&self, target: &Self) -> bool {
726 self.element_type.is_coercible_to(&target.element_type)
727 }
728}
729
730#[derive(Debug, Clone, PartialEq, Eq)]
732pub struct PairType {
733 left_type: Type,
735 right_type: Type,
737}
738
739impl PairType {
740 pub fn new(left_type: impl Into<Type>, right_type: impl Into<Type>) -> Self {
742 Self {
743 left_type: left_type.into(),
744 right_type: right_type.into(),
745 }
746 }
747
748 pub fn left_type(&self) -> &Type {
750 &self.left_type
751 }
752
753 pub fn right_type(&self) -> &Type {
755 &self.right_type
756 }
757}
758
759impl fmt::Display for PairType {
760 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761 write!(
762 f,
763 "Pair[{left}, {right}]",
764 left = self.left_type,
765 right = self.right_type
766 )?;
767
768 Ok(())
769 }
770}
771
772impl Coercible for PairType {
773 fn is_coercible_to(&self, target: &Self) -> bool {
774 self.left_type.is_coercible_to(&target.left_type)
775 && self.right_type.is_coercible_to(&target.right_type)
776 }
777}
778
779#[derive(Debug, Clone, PartialEq, Eq)]
781pub struct MapType {
782 key_type: Type,
784 value_type: Type,
786}
787
788impl MapType {
789 pub fn new(key_type: impl Into<Type>, value_type: impl Into<Type>) -> Self {
791 Self {
792 key_type: key_type.into(),
793 value_type: value_type.into(),
794 }
795 }
796
797 pub fn key_type(&self) -> &Type {
799 &self.key_type
800 }
801
802 pub fn value_type(&self) -> &Type {
804 &self.value_type
805 }
806}
807
808impl fmt::Display for MapType {
809 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810 write!(
811 f,
812 "Map[{key}, {value}]",
813 key = self.key_type,
814 value = self.value_type
815 )?;
816
817 Ok(())
818 }
819}
820
821impl Coercible for MapType {
822 fn is_coercible_to(&self, target: &Self) -> bool {
823 self.key_type.is_coercible_to(&target.key_type)
824 && self.value_type.is_coercible_to(&target.value_type)
825 }
826}
827
828#[derive(Debug, PartialEq, Eq)]
830pub struct StructType {
831 name: Arc<String>,
833 members: IndexMap<String, Type>,
835}
836
837impl StructType {
838 pub fn new<N, T>(name: impl Into<String>, members: impl IntoIterator<Item = (N, T)>) -> Self
840 where
841 N: Into<String>,
842 T: Into<Type>,
843 {
844 Self {
845 name: Arc::new(name.into()),
846 members: members
847 .into_iter()
848 .map(|(n, ty)| (n.into(), ty.into()))
849 .collect(),
850 }
851 }
852
853 pub fn name(&self) -> &Arc<String> {
855 &self.name
856 }
857
858 pub fn members(&self) -> &IndexMap<String, Type> {
860 &self.members
861 }
862}
863
864impl fmt::Display for StructType {
865 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
866 write!(f, "{name}", name = self.name)
867 }
868}
869
870impl Coercible for StructType {
871 fn is_coercible_to(&self, target: &Self) -> bool {
872 if self.members.len() != target.members.len() {
873 return false;
874 }
875
876 self.members.iter().all(|(k, v)| {
877 target
878 .members
879 .get(k)
880 .map(|target| v.is_coercible_to(target))
881 .unwrap_or(false)
882 })
883 }
884}
885
886#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
888pub enum CallKind {
889 Task,
891 Workflow,
893}
894
895impl fmt::Display for CallKind {
896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897 match self {
898 Self::Task => write!(f, "task"),
899 Self::Workflow => write!(f, "workflow"),
900 }
901 }
902}
903
904#[derive(Debug, Clone, Eq)]
906pub struct CallType {
907 kind: CallKind,
909 namespace: Option<Arc<String>>,
911 name: Arc<String>,
913 specified: Arc<HashSet<String>>,
915 inputs: Arc<IndexMap<String, Input>>,
917 outputs: Arc<IndexMap<String, Output>>,
919}
920
921impl CallType {
922 pub fn new(
924 kind: CallKind,
925 name: impl Into<String>,
926 specified: Arc<HashSet<String>>,
927 inputs: Arc<IndexMap<String, Input>>,
928 outputs: Arc<IndexMap<String, Output>>,
929 ) -> Self {
930 Self {
931 kind,
932 namespace: None,
933 name: Arc::new(name.into()),
934 specified,
935 inputs,
936 outputs,
937 }
938 }
939
940 pub fn namespaced(
943 kind: CallKind,
944 namespace: impl Into<String>,
945 name: impl Into<String>,
946 specified: Arc<HashSet<String>>,
947 inputs: Arc<IndexMap<String, Input>>,
948 outputs: Arc<IndexMap<String, Output>>,
949 ) -> Self {
950 Self {
951 kind,
952 namespace: Some(Arc::new(namespace.into())),
953 name: Arc::new(name.into()),
954 specified,
955 inputs,
956 outputs,
957 }
958 }
959
960 pub fn kind(&self) -> CallKind {
962 self.kind
963 }
964
965 pub fn namespace(&self) -> Option<&str> {
969 self.namespace.as_ref().map(|ns| ns.as_str())
970 }
971
972 pub fn name(&self) -> &str {
974 &self.name
975 }
976
977 pub fn specified(&self) -> &HashSet<String> {
979 &self.specified
980 }
981
982 pub fn inputs(&self) -> &IndexMap<String, Input> {
984 &self.inputs
985 }
986
987 pub fn outputs(&self) -> &IndexMap<String, Output> {
989 &self.outputs
990 }
991
992 pub fn promote(&self, kind: PromotionKind) -> Self {
994 let mut ty = self.clone();
995 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
996 *output = Output::new(output.ty().promote(kind), output.name_span());
997 }
998
999 ty
1000 }
1001}
1002
1003impl Coercible for CallType {
1004 fn is_coercible_to(&self, _: &Self) -> bool {
1005 false
1007 }
1008}
1009
1010impl fmt::Display for CallType {
1011 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1012 if let Some(ns) = &self.namespace {
1013 write!(
1014 f,
1015 "call to {kind} `{ns}.{name}`",
1016 kind = self.kind,
1017 name = self.name,
1018 )
1019 } else {
1020 write!(
1021 f,
1022 "call to {kind} `{name}`",
1023 kind = self.kind,
1024 name = self.name,
1025 )
1026 }
1027 }
1028}
1029
1030impl PartialEq for CallType {
1031 fn eq(&self, other: &Self) -> bool {
1032 std::ptr::eq(self, other)
1034 }
1035}
1036
1037#[cfg(test)]
1038mod test {
1039 use pretty_assertions::assert_eq;
1040
1041 use super::*;
1042
1043 #[test]
1044 fn primitive_type_display() {
1045 assert_eq!(PrimitiveType::Boolean.to_string(), "Boolean");
1046 assert_eq!(PrimitiveType::Integer.to_string(), "Int");
1047 assert_eq!(PrimitiveType::Float.to_string(), "Float");
1048 assert_eq!(PrimitiveType::String.to_string(), "String");
1049 assert_eq!(PrimitiveType::File.to_string(), "File");
1050 assert_eq!(PrimitiveType::Directory.to_string(), "Directory");
1051 assert_eq!(
1052 Type::from(PrimitiveType::Boolean).optional().to_string(),
1053 "Boolean?"
1054 );
1055 assert_eq!(
1056 Type::from(PrimitiveType::Integer).optional().to_string(),
1057 "Int?"
1058 );
1059 assert_eq!(
1060 Type::from(PrimitiveType::Float).optional().to_string(),
1061 "Float?"
1062 );
1063 assert_eq!(
1064 Type::from(PrimitiveType::String).optional().to_string(),
1065 "String?"
1066 );
1067 assert_eq!(
1068 Type::from(PrimitiveType::File).optional().to_string(),
1069 "File?"
1070 );
1071 assert_eq!(
1072 Type::from(PrimitiveType::Directory).optional().to_string(),
1073 "Directory?"
1074 );
1075 }
1076
1077 #[test]
1078 fn array_type_display() {
1079 assert_eq!(
1080 ArrayType::new(PrimitiveType::String).to_string(),
1081 "Array[String]"
1082 );
1083 assert_eq!(
1084 ArrayType::non_empty(PrimitiveType::String).to_string(),
1085 "Array[String]+"
1086 );
1087
1088 let ty: Type = ArrayType::new(ArrayType::new(PrimitiveType::String)).into();
1089 assert_eq!(ty.to_string(), "Array[Array[String]]");
1090
1091 let ty = Type::from(ArrayType::non_empty(
1092 Type::from(ArrayType::non_empty(
1093 Type::from(PrimitiveType::String).optional(),
1094 ))
1095 .optional(),
1096 ))
1097 .optional();
1098 assert_eq!(ty.to_string(), "Array[Array[String?]+?]+?");
1099 }
1100
1101 #[test]
1102 fn pair_type_display() {
1103 assert_eq!(
1104 PairType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1105 "Pair[String, Boolean]"
1106 );
1107
1108 let ty: Type = PairType::new(
1109 ArrayType::new(PrimitiveType::String),
1110 ArrayType::new(PrimitiveType::String),
1111 )
1112 .into();
1113 assert_eq!(ty.to_string(), "Pair[Array[String], Array[String]]");
1114
1115 let ty = Type::from(PairType::new(
1116 Type::from(ArrayType::non_empty(
1117 Type::from(PrimitiveType::File).optional(),
1118 ))
1119 .optional(),
1120 Type::from(ArrayType::non_empty(
1121 Type::from(PrimitiveType::File).optional(),
1122 ))
1123 .optional(),
1124 ))
1125 .optional();
1126 assert_eq!(ty.to_string(), "Pair[Array[File?]+?, Array[File?]+?]?");
1127 }
1128
1129 #[test]
1130 fn map_type_display() {
1131 assert_eq!(
1132 MapType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1133 "Map[String, Boolean]"
1134 );
1135
1136 let ty: Type = MapType::new(
1137 PrimitiveType::Boolean,
1138 ArrayType::new(PrimitiveType::String),
1139 )
1140 .into();
1141 assert_eq!(ty.to_string(), "Map[Boolean, Array[String]]");
1142
1143 let ty: Type = Type::from(MapType::new(
1144 PrimitiveType::String,
1145 Type::from(ArrayType::non_empty(
1146 Type::from(PrimitiveType::File).optional(),
1147 ))
1148 .optional(),
1149 ))
1150 .optional();
1151 assert_eq!(ty.to_string(), "Map[String, Array[File?]+?]?");
1152 }
1153
1154 #[test]
1155 fn struct_type_display() {
1156 assert_eq!(
1157 StructType::new("Foobar", std::iter::empty::<(String, Type)>()).to_string(),
1158 "Foobar"
1159 );
1160 }
1161
1162 #[test]
1163 fn object_type_display() {
1164 assert_eq!(Type::Object.to_string(), "Object");
1165 assert_eq!(Type::OptionalObject.to_string(), "Object?");
1166 }
1167
1168 #[test]
1169 fn union_type_display() {
1170 assert_eq!(Type::Union.to_string(), "Union");
1171 }
1172
1173 #[test]
1174 fn none_type_display() {
1175 assert_eq!(Type::None.to_string(), "None");
1176 }
1177
1178 #[test]
1179 fn primitive_type_coercion() {
1180 for ty in [
1183 Type::from(PrimitiveType::Boolean),
1184 PrimitiveType::Directory.into(),
1185 PrimitiveType::File.into(),
1186 PrimitiveType::Float.into(),
1187 PrimitiveType::Integer.into(),
1188 PrimitiveType::String.into(),
1189 ] {
1190 assert!(ty.is_coercible_to(&ty));
1191 assert!(ty.optional().is_coercible_to(&ty.optional()));
1192 assert!(ty.is_coercible_to(&ty.optional()));
1193 assert!(!ty.optional().is_coercible_to(&ty));
1194 }
1195
1196 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::File));
1198 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::Directory));
1199 assert!(PrimitiveType::Integer.is_coercible_to(&PrimitiveType::Float));
1200 assert!(PrimitiveType::File.is_coercible_to(&PrimitiveType::String));
1201 assert!(PrimitiveType::Directory.is_coercible_to(&PrimitiveType::String));
1202 assert!(!PrimitiveType::Float.is_coercible_to(&PrimitiveType::Integer));
1203 }
1204
1205 #[test]
1206 fn object_type_coercion() {
1207 assert!(Type::Object.is_coercible_to(&Type::Object));
1208 assert!(Type::Object.is_coercible_to(&Type::OptionalObject));
1209 assert!(Type::OptionalObject.is_coercible_to(&Type::OptionalObject));
1210 assert!(!Type::OptionalObject.is_coercible_to(&Type::Object));
1211
1212 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1214 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1215
1216 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1218 assert!(!Type::Object.is_coercible_to(&ty));
1219
1220 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1222 assert!(Type::Object.is_coercible_to(&ty));
1223
1224 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1226 assert!(Type::OptionalObject.is_coercible_to(&ty));
1227
1228 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1230 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1231
1232 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1234 assert!(Type::Object.is_coercible_to(&ty));
1235
1236 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1238 assert!(Type::Object.is_coercible_to(&ty));
1239
1240 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1242 assert!(Type::OptionalObject.is_coercible_to(&ty));
1243
1244 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1246 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1247 }
1248
1249 #[test]
1250 fn array_type_coercion() {
1251 assert!(
1253 ArrayType::new(PrimitiveType::String)
1254 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1255 );
1256 assert!(
1257 ArrayType::new(PrimitiveType::File)
1258 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1259 );
1260 assert!(
1261 ArrayType::new(PrimitiveType::String)
1262 .is_coercible_to(&ArrayType::new(PrimitiveType::File))
1263 );
1264
1265 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1267 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1268 assert!(type1.is_coercible_to(&type2));
1269 assert!(!type2.is_coercible_to(&type1));
1270
1271 let type1: Type = ArrayType::new(type1).into();
1273 let type2 = ArrayType::new(type2).into();
1274 assert!(type1.is_coercible_to(&type2));
1275 assert!(!type2.is_coercible_to(&type1));
1276
1277 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1279 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).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::String).optional()).into();
1286 assert!(type1.is_coercible_to(&type2));
1287 assert!(!type2.is_coercible_to(&type1));
1288
1289 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1291 let type2 = ArrayType::new(PrimitiveType::String).into();
1292 assert!(type1.is_coercible_to(&type2));
1293 assert!(type2.is_coercible_to(&type1));
1294
1295 let type1 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1297 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1298 assert!(type1.is_coercible_to(&type2));
1299 assert!(type2.is_coercible_to(&type1));
1300
1301 let type1: Type = ArrayType::new(PrimitiveType::String).into();
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
1308 #[test]
1309 fn pair_type_coercion() {
1310 assert!(
1312 PairType::new(PrimitiveType::String, PrimitiveType::String)
1313 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1314 );
1315 assert!(
1316 PairType::new(PrimitiveType::String, PrimitiveType::String).is_coercible_to(
1317 &PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1318 )
1319 );
1320 assert!(
1321 PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1322 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1323 );
1324
1325 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1327 let type2 = PairType::new(
1328 Type::from(PrimitiveType::File).optional(),
1329 Type::from(PrimitiveType::Directory).optional(),
1330 )
1331 .into();
1332 assert!(type1.is_coercible_to(&type2));
1333 assert!(!type2.is_coercible_to(&type1));
1334
1335 let type1: Type = PairType::new(type1.clone(), type1).into();
1337 let type2 = PairType::new(type2.clone(), type2).into();
1338 assert!(type1.is_coercible_to(&type2));
1339 assert!(!type2.is_coercible_to(&type1));
1340
1341 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1343 let type2 = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1344 assert!(type1.is_coercible_to(&type2));
1345 assert!(type2.is_coercible_to(&type1));
1346
1347 let type1 =
1349 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1350 let type2 =
1351 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1352 assert!(type1.is_coercible_to(&type2));
1353 assert!(type2.is_coercible_to(&type1));
1354
1355 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1357 let type2 =
1358 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1359 assert!(type1.is_coercible_to(&type2));
1360 assert!(!type2.is_coercible_to(&type1));
1361 }
1362
1363 #[test]
1364 fn map_type_coercion() {
1365 assert!(
1367 MapType::new(PrimitiveType::String, PrimitiveType::String)
1368 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1369 );
1370 assert!(
1371 MapType::new(PrimitiveType::String, PrimitiveType::String)
1372 .is_coercible_to(&MapType::new(PrimitiveType::File, PrimitiveType::Directory))
1373 );
1374 assert!(
1375 MapType::new(PrimitiveType::File, PrimitiveType::Directory)
1376 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1377 );
1378
1379 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1381 let type2 = MapType::new(
1382 Type::from(PrimitiveType::File).optional(),
1383 Type::from(PrimitiveType::Directory).optional(),
1384 )
1385 .into();
1386 assert!(type1.is_coercible_to(&type2));
1387 assert!(!type2.is_coercible_to(&type1));
1388
1389 let type1: Type = MapType::new(PrimitiveType::String, type1).into();
1391 let type2 = MapType::new(PrimitiveType::Directory, type2).into();
1392 assert!(type1.is_coercible_to(&type2));
1393 assert!(!type2.is_coercible_to(&type1));
1394
1395 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1397 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1398 assert!(type1.is_coercible_to(&type2));
1399 assert!(type2.is_coercible_to(&type1));
1400
1401 let type1: Type =
1403 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1404 let type2: Type =
1405 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1406 assert!(type1.is_coercible_to(&type2));
1407 assert!(type2.is_coercible_to(&type1));
1408
1409 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1411 let type2 =
1412 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1413 assert!(type1.is_coercible_to(&type2));
1414 assert!(!type2.is_coercible_to(&type1));
1415
1416 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1418 let type2 = StructType::new(
1419 "Foo",
1420 [
1421 ("foo", PrimitiveType::Integer),
1422 ("bar", PrimitiveType::Integer),
1423 ("baz", PrimitiveType::Integer),
1424 ],
1425 )
1426 .into();
1427 assert!(type1.is_coercible_to(&type2));
1428
1429 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1431 let type2 = StructType::new(
1432 "Foo",
1433 [
1434 ("foo", PrimitiveType::Integer),
1435 ("bar", PrimitiveType::String),
1436 ("baz", PrimitiveType::Integer),
1437 ],
1438 )
1439 .into();
1440 assert!(!type1.is_coercible_to(&type2));
1441
1442 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1444 let type2 = StructType::new(
1445 "Foo",
1446 [
1447 ("foo", PrimitiveType::Integer),
1448 ("bar", PrimitiveType::Integer),
1449 ("baz", PrimitiveType::Integer),
1450 ],
1451 )
1452 .into();
1453 assert!(!type1.is_coercible_to(&type2));
1454
1455 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1457 assert!(type1.is_coercible_to(&Type::Object));
1458
1459 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1461 assert!(type1.is_coercible_to(&Type::OptionalObject));
1462
1463 let type1: Type =
1465 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1466 assert!(type1.is_coercible_to(&Type::OptionalObject));
1467
1468 let type1: Type =
1470 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1471 assert!(!type1.is_coercible_to(&Type::Object));
1472
1473 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1475 assert!(!type1.is_coercible_to(&Type::Object));
1476 }
1477
1478 #[test]
1479 fn struct_type_coercion() {
1480 let type1: Type = StructType::new(
1482 "Foo",
1483 [
1484 ("foo", PrimitiveType::String),
1485 ("bar", PrimitiveType::String),
1486 ("baz", PrimitiveType::Integer),
1487 ],
1488 )
1489 .into();
1490 let type2 = StructType::new(
1491 "Foo",
1492 [
1493 ("foo", PrimitiveType::String),
1494 ("bar", PrimitiveType::String),
1495 ("baz", PrimitiveType::Integer),
1496 ],
1497 )
1498 .into();
1499 assert!(type1.is_coercible_to(&type2));
1500 assert!(type2.is_coercible_to(&type1));
1501
1502 let type1: Type = StructType::new(
1504 "Foo",
1505 [
1506 ("foo", PrimitiveType::String),
1507 ("bar", PrimitiveType::String),
1508 ("baz", PrimitiveType::Integer),
1509 ],
1510 )
1511 .into();
1512 let type2 = Type::from(StructType::new(
1513 "Foo",
1514 [
1515 ("foo", PrimitiveType::String),
1516 ("bar", PrimitiveType::String),
1517 ("baz", PrimitiveType::Integer),
1518 ],
1519 ))
1520 .optional();
1521 assert!(type1.is_coercible_to(&type2));
1522 assert!(!type2.is_coercible_to(&type1));
1523
1524 let type1: Type = Type::from(StructType::new(
1526 "Foo",
1527 [
1528 ("foo", PrimitiveType::String),
1529 ("bar", PrimitiveType::String),
1530 ("baz", PrimitiveType::Integer),
1531 ],
1532 ))
1533 .optional();
1534 let type2 = Type::from(StructType::new(
1535 "Foo",
1536 [
1537 ("foo", PrimitiveType::String),
1538 ("bar", PrimitiveType::String),
1539 ("baz", PrimitiveType::Integer),
1540 ],
1541 ))
1542 .optional();
1543 assert!(type1.is_coercible_to(&type2));
1544 assert!(type2.is_coercible_to(&type1));
1545
1546 let type1: Type = StructType::new(
1548 "Foo",
1549 [
1550 ("foo", PrimitiveType::String),
1551 ("bar", PrimitiveType::String),
1552 ("baz", PrimitiveType::Integer),
1553 ],
1554 )
1555 .into();
1556 let type2 = StructType::new(
1557 "Bar",
1558 [
1559 ("foo", PrimitiveType::File),
1560 ("bar", PrimitiveType::Directory),
1561 ("baz", PrimitiveType::Float),
1562 ],
1563 )
1564 .into();
1565 assert!(type1.is_coercible_to(&type2));
1566 assert!(!type2.is_coercible_to(&type1));
1567
1568 let type1: Type = StructType::new(
1570 "Foo",
1571 [
1572 ("foo", PrimitiveType::String),
1573 ("bar", PrimitiveType::String),
1574 ("baz", PrimitiveType::Integer),
1575 ],
1576 )
1577 .into();
1578 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1579 assert!(!type1.is_coercible_to(&type2));
1580 assert!(!type2.is_coercible_to(&type1));
1581
1582 let type1: Type = StructType::new(
1584 "Foo",
1585 [
1586 ("foo", PrimitiveType::String),
1587 ("bar", PrimitiveType::String),
1588 ("baz", PrimitiveType::String),
1589 ],
1590 )
1591 .into();
1592 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1593 assert!(type1.is_coercible_to(&type2));
1594
1595 let type1: Type = StructType::new(
1597 "Foo",
1598 [
1599 ("foo", PrimitiveType::String),
1600 ("bar", PrimitiveType::Integer),
1601 ("baz", PrimitiveType::String),
1602 ],
1603 )
1604 .into();
1605 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1606 assert!(!type1.is_coercible_to(&type2));
1607
1608 let type1: Type = StructType::new(
1610 "Foo",
1611 [
1612 ("foo", PrimitiveType::String),
1613 ("bar", PrimitiveType::String),
1614 ("baz", PrimitiveType::String),
1615 ],
1616 )
1617 .into();
1618 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1619 assert!(!type1.is_coercible_to(&type2));
1620
1621 assert!(type1.is_coercible_to(&Type::Object));
1623
1624 assert!(type1.is_coercible_to(&Type::OptionalObject));
1626
1627 let type1: Type =
1629 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1630 assert!(type1.is_coercible_to(&Type::OptionalObject));
1631
1632 assert!(!type1.is_coercible_to(&Type::Object));
1634 }
1635
1636 #[test]
1637 fn union_type_coercion() {
1638 for ty in [
1640 Type::from(PrimitiveType::Boolean),
1641 PrimitiveType::Directory.into(),
1642 PrimitiveType::File.into(),
1643 PrimitiveType::Float.into(),
1644 PrimitiveType::Integer.into(),
1645 PrimitiveType::String.into(),
1646 ] {
1647 assert!(Type::Union.is_coercible_to(&ty));
1648 assert!(Type::Union.is_coercible_to(&ty.optional()));
1649 assert!(ty.is_coercible_to(&Type::Union));
1650 }
1651
1652 for optional in [true, false] {
1653 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1655 let ty = if optional { ty.optional() } else { ty };
1656
1657 let coercible = Type::Union.is_coercible_to(&ty);
1658 assert!(coercible);
1659
1660 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1662 let ty = if optional { ty.optional() } else { ty };
1663 let coercible = Type::Union.is_coercible_to(&ty);
1664 assert!(coercible);
1665
1666 let ty: Type = MapType::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 = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1674 let ty = if optional { ty.optional() } else { ty };
1675 let coercible = Type::Union.is_coercible_to(&ty);
1676 assert!(coercible);
1677 }
1678 }
1679
1680 #[test]
1681 fn none_type_coercion() {
1682 for ty in [
1684 Type::from(PrimitiveType::Boolean),
1685 PrimitiveType::Directory.into(),
1686 PrimitiveType::File.into(),
1687 PrimitiveType::Float.into(),
1688 PrimitiveType::Integer.into(),
1689 PrimitiveType::String.into(),
1690 ] {
1691 assert!(!Type::None.is_coercible_to(&ty));
1692 assert!(Type::None.is_coercible_to(&ty.optional()));
1693 assert!(!ty.is_coercible_to(&Type::None));
1694 }
1695
1696 for optional in [true, false] {
1697 let ty: Type = ArrayType::new(PrimitiveType::String).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 = PairType::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 = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).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 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1729 let ty = if optional { ty.optional() } else { ty };
1730 let coercible = Type::None.is_coercible_to(&ty);
1731 if optional {
1732 assert!(coercible);
1733 } else {
1734 assert!(!coercible);
1735 }
1736 }
1737 }
1738
1739 #[test]
1740 fn primitive_equality() {
1741 for ty in [
1742 Type::from(PrimitiveType::Boolean),
1743 PrimitiveType::Directory.into(),
1744 PrimitiveType::File.into(),
1745 PrimitiveType::Float.into(),
1746 PrimitiveType::Integer.into(),
1747 PrimitiveType::String.into(),
1748 ] {
1749 assert!(ty.eq(&ty));
1750 assert!(!ty.optional().eq(&ty));
1751 assert!(!ty.eq(&ty.optional()));
1752 assert!(ty.optional().eq(&ty.optional()));
1753 assert!(!ty.eq(&Type::Object));
1754 assert!(!ty.eq(&Type::OptionalObject));
1755 assert!(!ty.eq(&Type::Union));
1756 assert!(!ty.eq(&Type::None));
1757 }
1758 }
1759
1760 #[test]
1761 fn array_equality() {
1762 let a: Type = ArrayType::new(PrimitiveType::String).into();
1764 let b: Type = ArrayType::new(PrimitiveType::String).into();
1765 assert!(a.eq(&b));
1766 assert!(!a.optional().eq(&b));
1767 assert!(!a.eq(&b.optional()));
1768 assert!(a.optional().eq(&b.optional()));
1769
1770 let a: Type = ArrayType::new(a).into();
1772 let b: Type = ArrayType::new(b).into();
1773 assert!(a.eq(&b));
1774
1775 let a: Type = ArrayType::non_empty(a).into();
1777 let b: Type = ArrayType::non_empty(b).into();
1778 assert!(a.eq(&b));
1779
1780 let a: Type = ArrayType::new(PrimitiveType::String).into();
1782 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1783 assert!(!a.eq(&b));
1784
1785 let a: Type = ArrayType::new(PrimitiveType::String).into();
1787 let b: Type = ArrayType::new(PrimitiveType::Integer).into();
1788 assert!(!a.eq(&b));
1789
1790 assert!(!a.eq(&Type::Object));
1791 assert!(!a.eq(&Type::OptionalObject));
1792 assert!(!a.eq(&Type::Union));
1793 assert!(!a.eq(&Type::None));
1794 }
1795
1796 #[test]
1797 fn pair_equality() {
1798 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1800 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1801 assert!(a.eq(&b));
1802 assert!(!a.optional().eq(&b));
1803 assert!(!a.eq(&b.optional()));
1804 assert!(a.optional().eq(&b.optional()));
1805
1806 let a: Type = PairType::new(a.clone(), a).into();
1809 let b: Type = PairType::new(b.clone(), b).into();
1810 assert!(a.eq(&b));
1811
1812 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1814 let b: Type =
1815 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1816 assert!(!a.eq(&b));
1817
1818 assert!(!a.eq(&Type::Object));
1819 assert!(!a.eq(&Type::OptionalObject));
1820 assert!(!a.eq(&Type::Union));
1821 assert!(!a.eq(&Type::None));
1822 }
1823
1824 #[test]
1825 fn map_equality() {
1826 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1828 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1829 assert!(a.eq(&b));
1830 assert!(!a.optional().eq(&b));
1831 assert!(!a.eq(&b.optional()));
1832 assert!(a.optional().eq(&b.optional()));
1833
1834 let a: Type = MapType::new(PrimitiveType::File, a).into();
1836 let b = MapType::new(PrimitiveType::File, b).into();
1837 assert!(a.eq(&b));
1838
1839 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1841 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1842 assert!(!a.eq(&b));
1843
1844 assert!(!a.eq(&Type::Object));
1845 assert!(!a.eq(&Type::OptionalObject));
1846 assert!(!a.eq(&Type::Union));
1847 assert!(!a.eq(&Type::None));
1848 }
1849
1850 #[test]
1851 fn struct_equality() {
1852 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1853 assert!(a.eq(&a));
1854 assert!(!a.optional().eq(&a));
1855 assert!(!a.eq(&a.optional()));
1856 assert!(a.optional().eq(&a.optional()));
1857
1858 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1859 assert!(a.eq(&b));
1860 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1861 assert!(!a.eq(&b));
1862 }
1863
1864 #[test]
1865 fn object_equality() {
1866 assert!(Type::Object.eq(&Type::Object));
1867 assert!(!Type::OptionalObject.eq(&Type::Object));
1868 assert!(!Type::Object.eq(&Type::OptionalObject));
1869 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1870 }
1871
1872 #[test]
1873 fn union_equality() {
1874 assert!(Type::Union.eq(&Type::Union));
1875 assert!(!Type::None.eq(&Type::Union));
1876 assert!(!Type::Union.eq(&Type::None));
1877 assert!(Type::None.eq(&Type::None));
1878 }
1879}