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 && let Some(ty) = this.common_type(other)
307 {
308 return Some(Self::Compound(ty, self.is_optional()));
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)
413 | (Self::Compound(src, false), Self::OptionalObject)
414 | (Self::Compound(src, _), Self::OptionalObject) => match src {
415 CompoundType::Map(src) => {
416 src.key_type.is_coercible_to(&PrimitiveType::String.into())
417 }
418 CompoundType::Struct(_) => true,
419 _ => false,
420 },
421
422 (Self::Object, Self::Compound(target, _))
428 | (Self::OptionalObject, Self::Compound(target, true)) => {
429 match target {
430 CompoundType::Map(target) => {
431 Type::from(PrimitiveType::String).is_coercible_to(&target.key_type)
432 }
433 CompoundType::Struct(_) => {
434 true
436 }
437 _ => false,
438 }
439 }
440
441 (Self::Union, _) | (_, Self::Union) => true,
443
444 (Self::None, ty) if ty.is_optional() => true,
446
447 _ => false,
449 }
450 }
451}
452
453impl From<PrimitiveType> for Type {
454 fn from(value: PrimitiveType) -> Self {
455 Self::Primitive(value, false)
456 }
457}
458
459impl From<CompoundType> for Type {
460 fn from(value: CompoundType) -> Self {
461 Self::Compound(value, false)
462 }
463}
464
465impl From<ArrayType> for Type {
466 fn from(value: ArrayType) -> Self {
467 Self::Compound(value.into(), false)
468 }
469}
470
471impl From<PairType> for Type {
472 fn from(value: PairType) -> Self {
473 Self::Compound(value.into(), false)
474 }
475}
476
477impl From<MapType> for Type {
478 fn from(value: MapType) -> Self {
479 Self::Compound(value.into(), false)
480 }
481}
482
483impl From<StructType> for Type {
484 fn from(value: StructType) -> Self {
485 Self::Compound(value.into(), false)
486 }
487}
488
489impl From<CallType> for Type {
490 fn from(value: CallType) -> Self {
491 Self::Call(value)
492 }
493}
494
495#[derive(Debug, Clone, PartialEq, Eq)]
497pub enum CompoundType {
498 Array(ArrayType),
500 Pair(Arc<PairType>),
502 Map(Arc<MapType>),
504 Struct(Arc<StructType>),
506}
507
508impl CompoundType {
509 pub fn as_array(&self) -> Option<&ArrayType> {
513 match self {
514 Self::Array(ty) => Some(ty),
515 _ => None,
516 }
517 }
518
519 pub fn as_pair(&self) -> Option<&PairType> {
523 match self {
524 Self::Pair(ty) => Some(ty),
525 _ => None,
526 }
527 }
528
529 pub fn as_map(&self) -> Option<&MapType> {
533 match self {
534 Self::Map(ty) => Some(ty),
535 _ => None,
536 }
537 }
538
539 pub fn as_struct(&self) -> Option<&StructType> {
543 match self {
544 Self::Struct(ty) => Some(ty),
545 _ => None,
546 }
547 }
548
549 fn common_type(&self, other: &Self) -> Option<CompoundType> {
554 match (self, other) {
557 (Self::Array(this), Self::Array(other)) => {
558 let element_type = this.element_type.common_type(&other.element_type)?;
559 Some(ArrayType::new(element_type).into())
560 }
561 (Self::Pair(this), Self::Pair(other)) => {
562 let left_type = this.left_type.common_type(&other.left_type)?;
563 let right_type = this.right_type.common_type(&other.right_type)?;
564 Some(PairType::new(left_type, right_type).into())
565 }
566 (Self::Map(this), Self::Map(other)) => {
567 let key_type = this.key_type.common_type(&other.key_type)?;
568 let value_type = this.value_type.common_type(&other.value_type)?;
569 Some(MapType::new(key_type, value_type).into())
570 }
571 _ => None,
572 }
573 }
574}
575
576impl fmt::Display for CompoundType {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578 match self {
579 Self::Array(ty) => ty.fmt(f),
580 Self::Pair(ty) => ty.fmt(f),
581 Self::Map(ty) => ty.fmt(f),
582 Self::Struct(ty) => ty.fmt(f),
583 }
584 }
585}
586
587impl Coercible for CompoundType {
588 fn is_coercible_to(&self, target: &Self) -> bool {
589 match (self, target) {
590 (Self::Array(src), Self::Array(target)) => src.is_coercible_to(target),
593
594 (Self::Pair(src), Self::Pair(target)) => src.is_coercible_to(target),
597
598 (Self::Map(src), Self::Map(target)) => src.is_coercible_to(target),
601
602 (Self::Struct(src), Self::Struct(target)) => src.is_coercible_to(target),
605
606 (Self::Map(src), Self::Struct(target)) => {
609 if !src.key_type.is_coercible_to(&PrimitiveType::String.into()) {
610 return false;
611 }
612
613 if !target
615 .members
616 .values()
617 .all(|ty| src.value_type.is_coercible_to(ty))
618 {
619 return false;
620 }
621
622 true
624 }
625
626 (Self::Struct(src), Self::Map(target)) => {
629 if !Type::from(PrimitiveType::String).is_coercible_to(&target.key_type) {
630 return false;
631 }
632
633 if !src
635 .members
636 .values()
637 .all(|ty| ty.is_coercible_to(&target.value_type))
638 {
639 return false;
640 }
641
642 true
643 }
644
645 _ => false,
646 }
647 }
648}
649
650impl From<ArrayType> for CompoundType {
651 fn from(value: ArrayType) -> Self {
652 Self::Array(value)
653 }
654}
655
656impl From<PairType> for CompoundType {
657 fn from(value: PairType) -> Self {
658 Self::Pair(value.into())
659 }
660}
661
662impl From<MapType> for CompoundType {
663 fn from(value: MapType) -> Self {
664 Self::Map(value.into())
665 }
666}
667
668impl From<StructType> for CompoundType {
669 fn from(value: StructType) -> Self {
670 Self::Struct(value.into())
671 }
672}
673
674#[derive(Debug, Clone, PartialEq, Eq)]
676pub struct ArrayType {
677 element_type: Arc<Type>,
679 non_empty: bool,
681}
682
683impl ArrayType {
684 pub fn new(element_type: impl Into<Type>) -> Self {
686 Self {
687 element_type: Arc::new(element_type.into()),
688 non_empty: false,
689 }
690 }
691
692 pub fn non_empty(element_type: impl Into<Type>) -> Self {
694 Self {
695 element_type: Arc::new(element_type.into()),
696 non_empty: true,
697 }
698 }
699
700 pub fn element_type(&self) -> &Type {
702 &self.element_type
703 }
704
705 pub fn is_non_empty(&self) -> bool {
707 self.non_empty
708 }
709
710 pub fn unqualified(self) -> ArrayType {
712 Self {
713 element_type: self.element_type,
714 non_empty: false,
715 }
716 }
717}
718
719impl fmt::Display for ArrayType {
720 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
721 write!(f, "Array[{ty}]", ty = self.element_type)?;
722
723 if self.non_empty {
724 write!(f, "+")?;
725 }
726
727 Ok(())
728 }
729}
730
731impl Coercible for ArrayType {
732 fn is_coercible_to(&self, target: &Self) -> bool {
733 self.element_type.is_coercible_to(&target.element_type)
735 }
736}
737
738#[derive(Debug, Clone, PartialEq, Eq)]
740pub struct PairType {
741 left_type: Type,
743 right_type: Type,
745}
746
747impl PairType {
748 pub fn new(left_type: impl Into<Type>, right_type: impl Into<Type>) -> Self {
750 Self {
751 left_type: left_type.into(),
752 right_type: right_type.into(),
753 }
754 }
755
756 pub fn left_type(&self) -> &Type {
758 &self.left_type
759 }
760
761 pub fn right_type(&self) -> &Type {
763 &self.right_type
764 }
765}
766
767impl fmt::Display for PairType {
768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
769 write!(
770 f,
771 "Pair[{left}, {right}]",
772 left = self.left_type,
773 right = self.right_type
774 )?;
775
776 Ok(())
777 }
778}
779
780impl Coercible for PairType {
781 fn is_coercible_to(&self, target: &Self) -> bool {
782 self.left_type.is_coercible_to(&target.left_type)
783 && self.right_type.is_coercible_to(&target.right_type)
784 }
785}
786
787#[derive(Debug, Clone, PartialEq, Eq)]
789pub struct MapType {
790 key_type: Type,
792 value_type: Type,
794}
795
796impl MapType {
797 pub fn new(key_type: impl Into<Type>, value_type: impl Into<Type>) -> Self {
799 Self {
800 key_type: key_type.into(),
801 value_type: value_type.into(),
802 }
803 }
804
805 pub fn key_type(&self) -> &Type {
807 &self.key_type
808 }
809
810 pub fn value_type(&self) -> &Type {
812 &self.value_type
813 }
814}
815
816impl fmt::Display for MapType {
817 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
818 write!(
819 f,
820 "Map[{key}, {value}]",
821 key = self.key_type,
822 value = self.value_type
823 )?;
824
825 Ok(())
826 }
827}
828
829impl Coercible for MapType {
830 fn is_coercible_to(&self, target: &Self) -> bool {
831 self.key_type.is_coercible_to(&target.key_type)
832 && self.value_type.is_coercible_to(&target.value_type)
833 }
834}
835
836#[derive(Debug, PartialEq, Eq)]
838pub struct StructType {
839 name: Arc<String>,
841 members: IndexMap<String, Type>,
843}
844
845impl StructType {
846 pub fn new<N, T>(name: impl Into<String>, members: impl IntoIterator<Item = (N, T)>) -> Self
848 where
849 N: Into<String>,
850 T: Into<Type>,
851 {
852 Self {
853 name: Arc::new(name.into()),
854 members: members
855 .into_iter()
856 .map(|(n, ty)| (n.into(), ty.into()))
857 .collect(),
858 }
859 }
860
861 pub fn name(&self) -> &Arc<String> {
863 &self.name
864 }
865
866 pub fn members(&self) -> &IndexMap<String, Type> {
868 &self.members
869 }
870}
871
872impl fmt::Display for StructType {
873 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
874 write!(f, "{name}", name = self.name)
875 }
876}
877
878impl Coercible for StructType {
879 fn is_coercible_to(&self, target: &Self) -> bool {
880 if self.members.len() != target.members.len() {
881 return false;
882 }
883
884 self.members.iter().all(|(k, v)| {
885 target
886 .members
887 .get(k)
888 .map(|target| v.is_coercible_to(target))
889 .unwrap_or(false)
890 })
891 }
892}
893
894#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
896pub enum CallKind {
897 Task,
899 Workflow,
901}
902
903impl fmt::Display for CallKind {
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 match self {
906 Self::Task => write!(f, "task"),
907 Self::Workflow => write!(f, "workflow"),
908 }
909 }
910}
911
912#[derive(Debug, Clone, Eq)]
914pub struct CallType {
915 kind: CallKind,
917 namespace: Option<Arc<String>>,
919 name: Arc<String>,
921 specified: Arc<HashSet<String>>,
923 inputs: Arc<IndexMap<String, Input>>,
925 outputs: Arc<IndexMap<String, Output>>,
927}
928
929impl CallType {
930 pub fn new(
932 kind: CallKind,
933 name: impl Into<String>,
934 specified: Arc<HashSet<String>>,
935 inputs: Arc<IndexMap<String, Input>>,
936 outputs: Arc<IndexMap<String, Output>>,
937 ) -> Self {
938 Self {
939 kind,
940 namespace: None,
941 name: Arc::new(name.into()),
942 specified,
943 inputs,
944 outputs,
945 }
946 }
947
948 pub fn namespaced(
951 kind: CallKind,
952 namespace: impl Into<String>,
953 name: impl Into<String>,
954 specified: Arc<HashSet<String>>,
955 inputs: Arc<IndexMap<String, Input>>,
956 outputs: Arc<IndexMap<String, Output>>,
957 ) -> Self {
958 Self {
959 kind,
960 namespace: Some(Arc::new(namespace.into())),
961 name: Arc::new(name.into()),
962 specified,
963 inputs,
964 outputs,
965 }
966 }
967
968 pub fn kind(&self) -> CallKind {
970 self.kind
971 }
972
973 pub fn namespace(&self) -> Option<&str> {
977 self.namespace.as_ref().map(|ns| ns.as_str())
978 }
979
980 pub fn name(&self) -> &str {
982 &self.name
983 }
984
985 pub fn specified(&self) -> &HashSet<String> {
987 &self.specified
988 }
989
990 pub fn inputs(&self) -> &IndexMap<String, Input> {
992 &self.inputs
993 }
994
995 pub fn outputs(&self) -> &IndexMap<String, Output> {
997 &self.outputs
998 }
999
1000 pub fn promote(&self, kind: PromotionKind) -> Self {
1002 let mut ty = self.clone();
1003 for output in Arc::make_mut(&mut ty.outputs).values_mut() {
1004 *output = Output::new(output.ty().promote(kind), output.name_span());
1005 }
1006
1007 ty
1008 }
1009}
1010
1011impl Coercible for CallType {
1012 fn is_coercible_to(&self, _: &Self) -> bool {
1013 false
1015 }
1016}
1017
1018impl fmt::Display for CallType {
1019 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1020 if let Some(ns) = &self.namespace {
1021 write!(
1022 f,
1023 "call to {kind} `{ns}.{name}`",
1024 kind = self.kind,
1025 name = self.name,
1026 )
1027 } else {
1028 write!(
1029 f,
1030 "call to {kind} `{name}`",
1031 kind = self.kind,
1032 name = self.name,
1033 )
1034 }
1035 }
1036}
1037
1038impl PartialEq for CallType {
1039 fn eq(&self, other: &Self) -> bool {
1040 std::ptr::eq(self, other)
1042 }
1043}
1044
1045#[cfg(test)]
1046mod test {
1047 use pretty_assertions::assert_eq;
1048
1049 use super::*;
1050
1051 #[test]
1052 fn primitive_type_display() {
1053 assert_eq!(PrimitiveType::Boolean.to_string(), "Boolean");
1054 assert_eq!(PrimitiveType::Integer.to_string(), "Int");
1055 assert_eq!(PrimitiveType::Float.to_string(), "Float");
1056 assert_eq!(PrimitiveType::String.to_string(), "String");
1057 assert_eq!(PrimitiveType::File.to_string(), "File");
1058 assert_eq!(PrimitiveType::Directory.to_string(), "Directory");
1059 assert_eq!(
1060 Type::from(PrimitiveType::Boolean).optional().to_string(),
1061 "Boolean?"
1062 );
1063 assert_eq!(
1064 Type::from(PrimitiveType::Integer).optional().to_string(),
1065 "Int?"
1066 );
1067 assert_eq!(
1068 Type::from(PrimitiveType::Float).optional().to_string(),
1069 "Float?"
1070 );
1071 assert_eq!(
1072 Type::from(PrimitiveType::String).optional().to_string(),
1073 "String?"
1074 );
1075 assert_eq!(
1076 Type::from(PrimitiveType::File).optional().to_string(),
1077 "File?"
1078 );
1079 assert_eq!(
1080 Type::from(PrimitiveType::Directory).optional().to_string(),
1081 "Directory?"
1082 );
1083 }
1084
1085 #[test]
1086 fn array_type_display() {
1087 assert_eq!(
1088 ArrayType::new(PrimitiveType::String).to_string(),
1089 "Array[String]"
1090 );
1091 assert_eq!(
1092 ArrayType::non_empty(PrimitiveType::String).to_string(),
1093 "Array[String]+"
1094 );
1095
1096 let ty: Type = ArrayType::new(ArrayType::new(PrimitiveType::String)).into();
1097 assert_eq!(ty.to_string(), "Array[Array[String]]");
1098
1099 let ty = Type::from(ArrayType::non_empty(
1100 Type::from(ArrayType::non_empty(
1101 Type::from(PrimitiveType::String).optional(),
1102 ))
1103 .optional(),
1104 ))
1105 .optional();
1106 assert_eq!(ty.to_string(), "Array[Array[String?]+?]+?");
1107 }
1108
1109 #[test]
1110 fn pair_type_display() {
1111 assert_eq!(
1112 PairType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1113 "Pair[String, Boolean]"
1114 );
1115
1116 let ty: Type = PairType::new(
1117 ArrayType::new(PrimitiveType::String),
1118 ArrayType::new(PrimitiveType::String),
1119 )
1120 .into();
1121 assert_eq!(ty.to_string(), "Pair[Array[String], Array[String]]");
1122
1123 let ty = Type::from(PairType::new(
1124 Type::from(ArrayType::non_empty(
1125 Type::from(PrimitiveType::File).optional(),
1126 ))
1127 .optional(),
1128 Type::from(ArrayType::non_empty(
1129 Type::from(PrimitiveType::File).optional(),
1130 ))
1131 .optional(),
1132 ))
1133 .optional();
1134 assert_eq!(ty.to_string(), "Pair[Array[File?]+?, Array[File?]+?]?");
1135 }
1136
1137 #[test]
1138 fn map_type_display() {
1139 assert_eq!(
1140 MapType::new(PrimitiveType::String, PrimitiveType::Boolean).to_string(),
1141 "Map[String, Boolean]"
1142 );
1143
1144 let ty: Type = MapType::new(
1145 PrimitiveType::Boolean,
1146 ArrayType::new(PrimitiveType::String),
1147 )
1148 .into();
1149 assert_eq!(ty.to_string(), "Map[Boolean, Array[String]]");
1150
1151 let ty: Type = Type::from(MapType::new(
1152 PrimitiveType::String,
1153 Type::from(ArrayType::non_empty(
1154 Type::from(PrimitiveType::File).optional(),
1155 ))
1156 .optional(),
1157 ))
1158 .optional();
1159 assert_eq!(ty.to_string(), "Map[String, Array[File?]+?]?");
1160 }
1161
1162 #[test]
1163 fn struct_type_display() {
1164 assert_eq!(
1165 StructType::new("Foobar", std::iter::empty::<(String, Type)>()).to_string(),
1166 "Foobar"
1167 );
1168 }
1169
1170 #[test]
1171 fn object_type_display() {
1172 assert_eq!(Type::Object.to_string(), "Object");
1173 assert_eq!(Type::OptionalObject.to_string(), "Object?");
1174 }
1175
1176 #[test]
1177 fn union_type_display() {
1178 assert_eq!(Type::Union.to_string(), "Union");
1179 }
1180
1181 #[test]
1182 fn none_type_display() {
1183 assert_eq!(Type::None.to_string(), "None");
1184 }
1185
1186 #[test]
1187 fn primitive_type_coercion() {
1188 for ty in [
1191 Type::from(PrimitiveType::Boolean),
1192 PrimitiveType::Directory.into(),
1193 PrimitiveType::File.into(),
1194 PrimitiveType::Float.into(),
1195 PrimitiveType::Integer.into(),
1196 PrimitiveType::String.into(),
1197 ] {
1198 assert!(ty.is_coercible_to(&ty));
1199 assert!(ty.optional().is_coercible_to(&ty.optional()));
1200 assert!(ty.is_coercible_to(&ty.optional()));
1201 assert!(!ty.optional().is_coercible_to(&ty));
1202 }
1203
1204 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::File));
1206 assert!(PrimitiveType::String.is_coercible_to(&PrimitiveType::Directory));
1207 assert!(PrimitiveType::Integer.is_coercible_to(&PrimitiveType::Float));
1208 assert!(PrimitiveType::File.is_coercible_to(&PrimitiveType::String));
1209 assert!(PrimitiveType::Directory.is_coercible_to(&PrimitiveType::String));
1210 assert!(!PrimitiveType::Float.is_coercible_to(&PrimitiveType::Integer));
1211 }
1212
1213 #[test]
1214 fn object_type_coercion() {
1215 assert!(Type::Object.is_coercible_to(&Type::Object));
1216 assert!(Type::Object.is_coercible_to(&Type::OptionalObject));
1217 assert!(Type::OptionalObject.is_coercible_to(&Type::OptionalObject));
1218 assert!(!Type::OptionalObject.is_coercible_to(&Type::Object));
1219
1220 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1222 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1223
1224 let ty = MapType::new(PrimitiveType::File, PrimitiveType::String).into();
1226 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1227
1228 let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1230 assert!(!Type::Object.is_coercible_to(&ty));
1231
1232 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1234 assert!(Type::Object.is_coercible_to(&ty));
1235
1236 let ty = Type::from(MapType::new(PrimitiveType::File, PrimitiveType::String)).optional();
1238 assert!(Type::Object.is_coercible_to(&ty));
1239
1240 let ty = Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1242 assert!(Type::OptionalObject.is_coercible_to(&ty));
1243
1244 let ty = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1246 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1247
1248 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1250 assert!(Type::Object.is_coercible_to(&ty));
1251
1252 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1254 assert!(Type::Object.is_coercible_to(&ty));
1255
1256 let ty = Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1258 assert!(Type::OptionalObject.is_coercible_to(&ty));
1259
1260 let ty = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1262 assert!(!Type::OptionalObject.is_coercible_to(&ty));
1263 }
1264
1265 #[test]
1266 fn array_type_coercion() {
1267 assert!(
1269 ArrayType::new(PrimitiveType::String)
1270 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1271 );
1272 assert!(
1273 ArrayType::new(PrimitiveType::File)
1274 .is_coercible_to(&ArrayType::new(PrimitiveType::String))
1275 );
1276 assert!(
1277 ArrayType::new(PrimitiveType::String)
1278 .is_coercible_to(&ArrayType::new(PrimitiveType::File))
1279 );
1280
1281 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1283 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1284 assert!(type1.is_coercible_to(&type2));
1285 assert!(!type2.is_coercible_to(&type1));
1286
1287 let type1: Type = ArrayType::new(type1).into();
1289 let type2 = ArrayType::new(type2).into();
1290 assert!(type1.is_coercible_to(&type2));
1291 assert!(!type2.is_coercible_to(&type1));
1292
1293 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1295 let type2 = ArrayType::new(Type::from(PrimitiveType::File).optional()).into();
1296 assert!(type1.is_coercible_to(&type2));
1297 assert!(!type2.is_coercible_to(&type1));
1298
1299 let type1: Type = ArrayType::non_empty(PrimitiveType::String).into();
1301 let type2 = ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
1302 assert!(type1.is_coercible_to(&type2));
1303 assert!(!type2.is_coercible_to(&type1));
1304
1305 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1307 let type2 = ArrayType::new(PrimitiveType::String).into();
1308 assert!(type1.is_coercible_to(&type2));
1309 assert!(type2.is_coercible_to(&type1));
1310
1311 let type1 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1313 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1314 assert!(type1.is_coercible_to(&type2));
1315 assert!(type2.is_coercible_to(&type1));
1316
1317 let type1: Type = ArrayType::new(PrimitiveType::String).into();
1319 let type2 = Type::from(ArrayType::new(PrimitiveType::String)).optional();
1320 assert!(type1.is_coercible_to(&type2));
1321 assert!(!type2.is_coercible_to(&type1));
1322 }
1323
1324 #[test]
1325 fn pair_type_coercion() {
1326 assert!(
1328 PairType::new(PrimitiveType::String, PrimitiveType::String)
1329 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1330 );
1331 assert!(
1332 PairType::new(PrimitiveType::String, PrimitiveType::String).is_coercible_to(
1333 &PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1334 )
1335 );
1336 assert!(
1337 PairType::new(PrimitiveType::File, PrimitiveType::Directory)
1338 .is_coercible_to(&PairType::new(PrimitiveType::String, PrimitiveType::String))
1339 );
1340
1341 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1343 let type2 = PairType::new(
1344 Type::from(PrimitiveType::File).optional(),
1345 Type::from(PrimitiveType::Directory).optional(),
1346 )
1347 .into();
1348 assert!(type1.is_coercible_to(&type2));
1349 assert!(!type2.is_coercible_to(&type1));
1350
1351 let type1: Type = PairType::new(type1.clone(), type1).into();
1353 let type2 = PairType::new(type2.clone(), type2).into();
1354 assert!(type1.is_coercible_to(&type2));
1355 assert!(!type2.is_coercible_to(&type1));
1356
1357 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1359 let type2 = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1360 assert!(type1.is_coercible_to(&type2));
1361 assert!(type2.is_coercible_to(&type1));
1362
1363 let type1 =
1365 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1366 let type2 =
1367 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1368 assert!(type1.is_coercible_to(&type2));
1369 assert!(type2.is_coercible_to(&type1));
1370
1371 let type1: Type = PairType::new(PrimitiveType::String, PrimitiveType::String).into();
1373 let type2 =
1374 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1375 assert!(type1.is_coercible_to(&type2));
1376 assert!(!type2.is_coercible_to(&type1));
1377 }
1378
1379 #[test]
1380 fn map_type_coercion() {
1381 assert!(
1383 MapType::new(PrimitiveType::String, PrimitiveType::String)
1384 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1385 );
1386 assert!(
1387 MapType::new(PrimitiveType::String, PrimitiveType::String)
1388 .is_coercible_to(&MapType::new(PrimitiveType::File, PrimitiveType::Directory))
1389 );
1390 assert!(
1391 MapType::new(PrimitiveType::File, PrimitiveType::Directory)
1392 .is_coercible_to(&MapType::new(PrimitiveType::String, PrimitiveType::String))
1393 );
1394
1395 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1397 let type2 = MapType::new(
1398 Type::from(PrimitiveType::File).optional(),
1399 Type::from(PrimitiveType::Directory).optional(),
1400 )
1401 .into();
1402 assert!(type1.is_coercible_to(&type2));
1403 assert!(!type2.is_coercible_to(&type1));
1404
1405 let type1: Type = MapType::new(PrimitiveType::String, type1).into();
1407 let type2 = MapType::new(PrimitiveType::Directory, type2).into();
1408 assert!(type1.is_coercible_to(&type2));
1409 assert!(!type2.is_coercible_to(&type1));
1410
1411 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1413 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1414 assert!(type1.is_coercible_to(&type2));
1415 assert!(type2.is_coercible_to(&type1));
1416
1417 let type1: Type =
1419 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1420 let type2: Type =
1421 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1422 assert!(type1.is_coercible_to(&type2));
1423 assert!(type2.is_coercible_to(&type1));
1424
1425 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1427 let type2 =
1428 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::String)).optional();
1429 assert!(type1.is_coercible_to(&type2));
1430 assert!(!type2.is_coercible_to(&type1));
1431
1432 let type1: Type = MapType::new(PrimitiveType::String, 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::File, PrimitiveType::Integer).into();
1447 let type2 = StructType::new(
1448 "Foo",
1449 [
1450 ("foo", PrimitiveType::Integer),
1451 ("bar", PrimitiveType::Integer),
1452 ("baz", PrimitiveType::Integer),
1453 ],
1454 )
1455 .into();
1456 assert!(type1.is_coercible_to(&type2));
1457
1458 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1460 let type2 = StructType::new(
1461 "Foo",
1462 [
1463 ("foo", PrimitiveType::Integer),
1464 ("bar", PrimitiveType::String),
1465 ("baz", PrimitiveType::Integer),
1466 ],
1467 )
1468 .into();
1469 assert!(!type1.is_coercible_to(&type2));
1470
1471 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1473 let type2 = StructType::new(
1474 "Foo",
1475 [
1476 ("foo", PrimitiveType::Integer),
1477 ("bar", PrimitiveType::Integer),
1478 ("baz", PrimitiveType::Integer),
1479 ],
1480 )
1481 .into();
1482 assert!(!type1.is_coercible_to(&type2));
1483
1484 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1486 assert!(type1.is_coercible_to(&Type::Object));
1487
1488 let type1: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1490 assert!(type1.is_coercible_to(&Type::OptionalObject));
1491
1492 let type1: Type =
1494 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1495 assert!(type1.is_coercible_to(&Type::OptionalObject));
1496
1497 let type1: Type = MapType::new(PrimitiveType::File, PrimitiveType::Integer).into();
1499 assert!(type1.is_coercible_to(&Type::Object));
1500
1501 let type1: Type = MapType::new(PrimitiveType::File, PrimitiveType::Integer).into();
1503 assert!(type1.is_coercible_to(&Type::OptionalObject));
1504
1505 let type1: Type =
1507 Type::from(MapType::new(PrimitiveType::File, PrimitiveType::Integer)).optional();
1508 assert!(type1.is_coercible_to(&Type::OptionalObject));
1509
1510 let type1: Type =
1512 Type::from(MapType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1513 assert!(!type1.is_coercible_to(&Type::Object));
1514
1515 let type1: Type =
1517 Type::from(MapType::new(PrimitiveType::File, PrimitiveType::Integer)).optional();
1518 assert!(!type1.is_coercible_to(&Type::Object));
1519
1520 let type1: Type = MapType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
1522 assert!(!type1.is_coercible_to(&Type::Object));
1523 }
1524
1525 #[test]
1526 fn struct_type_coercion() {
1527 let type1: Type = StructType::new(
1529 "Foo",
1530 [
1531 ("foo", PrimitiveType::String),
1532 ("bar", PrimitiveType::String),
1533 ("baz", PrimitiveType::Integer),
1534 ],
1535 )
1536 .into();
1537 let type2 = StructType::new(
1538 "Foo",
1539 [
1540 ("foo", PrimitiveType::String),
1541 ("bar", PrimitiveType::String),
1542 ("baz", PrimitiveType::Integer),
1543 ],
1544 )
1545 .into();
1546 assert!(type1.is_coercible_to(&type2));
1547 assert!(type2.is_coercible_to(&type1));
1548
1549 let type1: Type = StructType::new(
1551 "Foo",
1552 [
1553 ("foo", PrimitiveType::String),
1554 ("bar", PrimitiveType::String),
1555 ("baz", PrimitiveType::Integer),
1556 ],
1557 )
1558 .into();
1559 let type2 = Type::from(StructType::new(
1560 "Foo",
1561 [
1562 ("foo", PrimitiveType::String),
1563 ("bar", PrimitiveType::String),
1564 ("baz", PrimitiveType::Integer),
1565 ],
1566 ))
1567 .optional();
1568 assert!(type1.is_coercible_to(&type2));
1569 assert!(!type2.is_coercible_to(&type1));
1570
1571 let type1: Type = Type::from(StructType::new(
1573 "Foo",
1574 [
1575 ("foo", PrimitiveType::String),
1576 ("bar", PrimitiveType::String),
1577 ("baz", PrimitiveType::Integer),
1578 ],
1579 ))
1580 .optional();
1581 let type2 = Type::from(StructType::new(
1582 "Foo",
1583 [
1584 ("foo", PrimitiveType::String),
1585 ("bar", PrimitiveType::String),
1586 ("baz", PrimitiveType::Integer),
1587 ],
1588 ))
1589 .optional();
1590 assert!(type1.is_coercible_to(&type2));
1591 assert!(type2.is_coercible_to(&type1));
1592
1593 let type1: Type = StructType::new(
1595 "Foo",
1596 [
1597 ("foo", PrimitiveType::String),
1598 ("bar", PrimitiveType::String),
1599 ("baz", PrimitiveType::Integer),
1600 ],
1601 )
1602 .into();
1603 let type2 = StructType::new(
1604 "Bar",
1605 [
1606 ("foo", PrimitiveType::File),
1607 ("bar", PrimitiveType::Directory),
1608 ("baz", PrimitiveType::Float),
1609 ],
1610 )
1611 .into();
1612 assert!(type1.is_coercible_to(&type2));
1613 assert!(!type2.is_coercible_to(&type1));
1614
1615 let type1: Type = StructType::new(
1617 "Foo",
1618 [
1619 ("foo", PrimitiveType::String),
1620 ("bar", PrimitiveType::String),
1621 ("baz", PrimitiveType::Integer),
1622 ],
1623 )
1624 .into();
1625 let type2 = StructType::new("Bar", [("baz", PrimitiveType::Float)]).into();
1626 assert!(!type1.is_coercible_to(&type2));
1627 assert!(!type2.is_coercible_to(&type1));
1628
1629 let type1: Type = StructType::new(
1631 "Foo",
1632 [
1633 ("foo", PrimitiveType::String),
1634 ("bar", PrimitiveType::String),
1635 ("baz", PrimitiveType::String),
1636 ],
1637 )
1638 .into();
1639 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1640 assert!(type1.is_coercible_to(&type2));
1641
1642 let type1: Type = StructType::new(
1644 "Foo",
1645 [
1646 ("foo", PrimitiveType::String),
1647 ("bar", PrimitiveType::String),
1648 ("baz", PrimitiveType::String),
1649 ],
1650 )
1651 .into();
1652 let type2 = MapType::new(PrimitiveType::File, PrimitiveType::String).into();
1653 assert!(type1.is_coercible_to(&type2));
1654
1655 let type1: Type = StructType::new(
1657 "Foo",
1658 [
1659 ("foo", PrimitiveType::String),
1660 ("bar", PrimitiveType::Integer),
1661 ("baz", PrimitiveType::String),
1662 ],
1663 )
1664 .into();
1665 let type2 = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1666 assert!(!type1.is_coercible_to(&type2));
1667
1668 let type1: Type = StructType::new(
1670 "Foo",
1671 [
1672 ("foo", PrimitiveType::String),
1673 ("bar", PrimitiveType::String),
1674 ("baz", PrimitiveType::String),
1675 ],
1676 )
1677 .into();
1678 let type2 = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1679 assert!(!type1.is_coercible_to(&type2));
1680
1681 assert!(type1.is_coercible_to(&Type::Object));
1683
1684 assert!(type1.is_coercible_to(&Type::OptionalObject));
1686
1687 let type1: Type =
1689 Type::from(StructType::new("Foo", [("foo", PrimitiveType::String)])).optional();
1690 assert!(type1.is_coercible_to(&Type::OptionalObject));
1691
1692 assert!(!type1.is_coercible_to(&Type::Object));
1694 }
1695
1696 #[test]
1697 fn union_type_coercion() {
1698 for ty in [
1700 Type::from(PrimitiveType::Boolean),
1701 PrimitiveType::Directory.into(),
1702 PrimitiveType::File.into(),
1703 PrimitiveType::Float.into(),
1704 PrimitiveType::Integer.into(),
1705 PrimitiveType::String.into(),
1706 ] {
1707 assert!(Type::Union.is_coercible_to(&ty));
1708 assert!(Type::Union.is_coercible_to(&ty.optional()));
1709 assert!(ty.is_coercible_to(&Type::Union));
1710 }
1711
1712 for optional in [true, false] {
1713 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1715 let ty = if optional { ty.optional() } else { ty };
1716
1717 let coercible = Type::Union.is_coercible_to(&ty);
1718 assert!(coercible);
1719
1720 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1722 let ty = if optional { ty.optional() } else { ty };
1723 let coercible = Type::Union.is_coercible_to(&ty);
1724 assert!(coercible);
1725
1726 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1728 let ty = if optional { ty.optional() } else { ty };
1729 let coercible = Type::Union.is_coercible_to(&ty);
1730 assert!(coercible);
1731
1732 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1734 let ty = if optional { ty.optional() } else { ty };
1735 let coercible = Type::Union.is_coercible_to(&ty);
1736 assert!(coercible);
1737 }
1738 }
1739
1740 #[test]
1741 fn none_type_coercion() {
1742 for ty in [
1744 Type::from(PrimitiveType::Boolean),
1745 PrimitiveType::Directory.into(),
1746 PrimitiveType::File.into(),
1747 PrimitiveType::Float.into(),
1748 PrimitiveType::Integer.into(),
1749 PrimitiveType::String.into(),
1750 ] {
1751 assert!(!Type::None.is_coercible_to(&ty));
1752 assert!(Type::None.is_coercible_to(&ty.optional()));
1753 assert!(!ty.is_coercible_to(&Type::None));
1754 }
1755
1756 for optional in [true, false] {
1757 let ty: Type = ArrayType::new(PrimitiveType::String).into();
1759 let ty = if optional { ty.optional() } else { ty };
1760 let coercible = Type::None.is_coercible_to(&ty);
1761 if optional {
1762 assert!(coercible);
1763 } else {
1764 assert!(!coercible);
1765 }
1766
1767 let ty: Type = PairType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1769 let ty = if optional { ty.optional() } else { ty };
1770 let coercible = Type::None.is_coercible_to(&ty);
1771 if optional {
1772 assert!(coercible);
1773 } else {
1774 assert!(!coercible);
1775 }
1776
1777 let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::Boolean).into();
1779 let ty = if optional { ty.optional() } else { ty };
1780 let coercible = Type::None.is_coercible_to(&ty);
1781 if optional {
1782 assert!(coercible);
1783 } else {
1784 assert!(!coercible);
1785 }
1786
1787 let ty: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1789 let ty = if optional { ty.optional() } else { ty };
1790 let coercible = Type::None.is_coercible_to(&ty);
1791 if optional {
1792 assert!(coercible);
1793 } else {
1794 assert!(!coercible);
1795 }
1796 }
1797 }
1798
1799 #[test]
1800 fn primitive_equality() {
1801 for ty in [
1802 Type::from(PrimitiveType::Boolean),
1803 PrimitiveType::Directory.into(),
1804 PrimitiveType::File.into(),
1805 PrimitiveType::Float.into(),
1806 PrimitiveType::Integer.into(),
1807 PrimitiveType::String.into(),
1808 ] {
1809 assert!(ty.eq(&ty));
1810 assert!(!ty.optional().eq(&ty));
1811 assert!(!ty.eq(&ty.optional()));
1812 assert!(ty.optional().eq(&ty.optional()));
1813 assert!(!ty.eq(&Type::Object));
1814 assert!(!ty.eq(&Type::OptionalObject));
1815 assert!(!ty.eq(&Type::Union));
1816 assert!(!ty.eq(&Type::None));
1817 }
1818 }
1819
1820 #[test]
1821 fn array_equality() {
1822 let a: Type = ArrayType::new(PrimitiveType::String).into();
1824 let b: Type = ArrayType::new(PrimitiveType::String).into();
1825 assert!(a.eq(&b));
1826 assert!(!a.optional().eq(&b));
1827 assert!(!a.eq(&b.optional()));
1828 assert!(a.optional().eq(&b.optional()));
1829
1830 let a: Type = ArrayType::new(a).into();
1832 let b: Type = ArrayType::new(b).into();
1833 assert!(a.eq(&b));
1834
1835 let a: Type = ArrayType::non_empty(a).into();
1837 let b: Type = ArrayType::non_empty(b).into();
1838 assert!(a.eq(&b));
1839
1840 let a: Type = ArrayType::new(PrimitiveType::String).into();
1842 let b: Type = ArrayType::non_empty(PrimitiveType::String).into();
1843 assert!(!a.eq(&b));
1844
1845 let a: Type = ArrayType::new(PrimitiveType::String).into();
1847 let b: Type = ArrayType::new(PrimitiveType::Integer).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 pair_equality() {
1858 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1860 let b: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1861 assert!(a.eq(&b));
1862 assert!(!a.optional().eq(&b));
1863 assert!(!a.eq(&b.optional()));
1864 assert!(a.optional().eq(&b.optional()));
1865
1866 let a: Type = PairType::new(a.clone(), a).into();
1869 let b: Type = PairType::new(b.clone(), b).into();
1870 assert!(a.eq(&b));
1871
1872 let a: Type = PairType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1874 let b: Type =
1875 Type::from(PairType::new(PrimitiveType::String, PrimitiveType::Integer)).optional();
1876 assert!(!a.eq(&b));
1877
1878 assert!(!a.eq(&Type::Object));
1879 assert!(!a.eq(&Type::OptionalObject));
1880 assert!(!a.eq(&Type::Union));
1881 assert!(!a.eq(&Type::None));
1882 }
1883
1884 #[test]
1885 fn map_equality() {
1886 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1888 let b = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1889 assert!(a.eq(&b));
1890 assert!(!a.optional().eq(&b));
1891 assert!(!a.eq(&b.optional()));
1892 assert!(a.optional().eq(&b.optional()));
1893
1894 let a: Type = MapType::new(PrimitiveType::File, a).into();
1896 let b = MapType::new(PrimitiveType::File, b).into();
1897 assert!(a.eq(&b));
1898
1899 let a: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1901 let b = MapType::new(PrimitiveType::Integer, PrimitiveType::String).into();
1902 assert!(!a.eq(&b));
1903
1904 assert!(!a.eq(&Type::Object));
1905 assert!(!a.eq(&Type::OptionalObject));
1906 assert!(!a.eq(&Type::Union));
1907 assert!(!a.eq(&Type::None));
1908 }
1909
1910 #[test]
1911 fn struct_equality() {
1912 let a: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1913 assert!(a.eq(&a));
1914 assert!(!a.optional().eq(&a));
1915 assert!(!a.eq(&a.optional()));
1916 assert!(a.optional().eq(&a.optional()));
1917
1918 let b: Type = StructType::new("Foo", [("foo", PrimitiveType::String)]).into();
1919 assert!(a.eq(&b));
1920 let b: Type = StructType::new("Bar", [("foo", PrimitiveType::String)]).into();
1921 assert!(!a.eq(&b));
1922 }
1923
1924 #[test]
1925 fn object_equality() {
1926 assert!(Type::Object.eq(&Type::Object));
1927 assert!(!Type::OptionalObject.eq(&Type::Object));
1928 assert!(!Type::Object.eq(&Type::OptionalObject));
1929 assert!(Type::OptionalObject.eq(&Type::OptionalObject));
1930 }
1931
1932 #[test]
1933 fn union_equality() {
1934 assert!(Type::Union.eq(&Type::Union));
1935 assert!(!Type::None.eq(&Type::Union));
1936 assert!(!Type::Union.eq(&Type::None));
1937 assert!(Type::None.eq(&Type::None));
1938 }
1939}