swamp_types/
calc_compat.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use crate::Type;
7use crate::type_kind::TypeKind;
8
9impl Type {
10    pub(crate) fn do_compatible_with(&self, other: &Self) -> bool {
11        if self.id == other.id {
12            return true;
13        }
14
15        match (&*self.kind, &*other.kind) {
16            // Direct comparisons for primitive types
17            (TypeKind::Int, TypeKind::Int) => true,
18            (TypeKind::Float, TypeKind::Float) => true,
19            (TypeKind::Bool, TypeKind::Bool) => true,
20            (TypeKind::String, TypeKind::String) => true,
21            (TypeKind::Unit, TypeKind::Unit) => true,
22
23            // For container types, we compare their structure but delegate inner compatibility
24            // checks to TypeCache.compatible_with
25            (TypeKind::Optional(_), TypeKind::Optional(_)) => true,
26
27            (TypeKind::VecStorage(_, cap_a), TypeKind::VecStorage(_, cap_b)) => {
28                true // cap_a >= cap_b // Vec with larger capacity is compatible with smaller requirement
29            }
30            (TypeKind::SparseStorage(_, cap_a), TypeKind::SparseStorage(_, cap_b)) => {
31                true // cap_a >= cap_b
32            }
33            (TypeKind::QueueStorage(_, cap_a), TypeKind::QueueStorage(_, cap_b)) => true,
34
35            (TypeKind::StackStorage(_, cap_a), TypeKind::StackStorage(_, cap_b)) => true,
36
37            (TypeKind::MapStorage(_, _, cap_a), TypeKind::MapStorage(_, _, cap_b)) => true,
38
39            (
40                TypeKind::GridStorage(_, rows_a, cols_a),
41                TypeKind::GridStorage(_, rows_b, cols_b),
42            ) => rows_a >= rows_b && cols_a >= cols_b,
43
44            (TypeKind::SliceView(_), TypeKind::SliceView(_)) => true,
45            (TypeKind::SparseView(_), TypeKind::SparseView(_)) => true,
46            (TypeKind::QueueView(_), TypeKind::QueueView(_)) => true,
47            (TypeKind::StackView(_), TypeKind::StackView(_)) => true,
48            (TypeKind::DynamicLengthVecView(_), TypeKind::DynamicLengthVecView(_)) => true,
49            (TypeKind::DynamicLengthMapView(_, _), TypeKind::DynamicLengthMapView(_, _)) => true,
50
51            (
52                TypeKind::FixedCapacityAndLengthArray(_, size_a),
53                TypeKind::FixedCapacityAndLengthArray(_, size_b),
54            ) => {
55                size_a == size_b // Fixed arrays must have the same size
56            }
57
58            (TypeKind::Tuple(elems_a), TypeKind::Tuple(elems_b)) => {
59                elems_a.len() == elems_b.len() // Tuples must have same length
60            }
61
62            (TypeKind::AnonymousStruct(anon_a), TypeKind::AnonymousStruct(anon_b)) => {
63                anon_a.field_name_sorted_fields.len() == anon_b.field_name_sorted_fields.len()
64                    && anon_a
65                        .field_name_sorted_fields
66                        .keys()
67                        .all(|key| anon_b.field_name_sorted_fields.contains_key(key))
68            }
69
70            (TypeKind::NamedStruct(named_a), TypeKind::NamedStruct(named_b)) => {
71                named_a.assigned_name == named_b.assigned_name
72                    && named_a.instantiated_type_parameters.len()
73                        == named_b.instantiated_type_parameters.len()
74            }
75
76            (TypeKind::Enum(enum_a), TypeKind::Enum(enum_b)) => {
77                enum_a.assigned_name == enum_b.assigned_name
78                    && enum_a.instantiated_type_parameters.len()
79                        == enum_b.instantiated_type_parameters.len()
80            }
81
82            (TypeKind::Function(sig_a), TypeKind::Function(sig_b)) => {
83                sig_a.parameters.len() == sig_b.parameters.len()
84            }
85
86            // Default case
87            _ => self.compatible_with_storage_and_view(other),
88        }
89    }
90
91    #[must_use]
92    pub fn compatible_with_storage_and_view(&self, other_view: &Self) -> bool {
93        let left_kind = self.lowest_common_denominator_vec_like_view();
94        let right_kind = self.lowest_common_denominator_vec_like_view();
95        if left_kind.is_some() && right_kind.is_some() {
96            let left = left_kind.unwrap();
97            let right = right_kind.unwrap();
98
99            return left == right;
100        }
101
102        match (&*self.kind, &*other_view.kind) {
103            (
104                TypeKind::MapStorage(key_a, value_a, _),
105                TypeKind::DynamicLengthMapView(key_b, value_b),
106            )
107            | (
108                TypeKind::DynamicLengthMapView(key_a, value_a),
109                TypeKind::MapStorage(key_b, value_b, _),
110            ) => key_a.do_compatible_with(key_b) && value_a.do_compatible_with(value_b),
111            _ => false,
112        }
113    }
114
115    // Helper method for lowest_common_denominator_view
116    #[must_use]
117    pub fn lowest_common_denominator_vec_like_view(&self) -> Option<TypeKind> {
118        match &*self.kind {
119            TypeKind::FixedCapacityAndLengthArray(inner, _size)
120            | TypeKind::QueueStorage(inner, _size)
121            | TypeKind::StackStorage(inner, _size)
122            | TypeKind::SparseStorage(inner, _size)
123            | TypeKind::VecStorage(inner, _size) => Some(TypeKind::SliceView(inner.clone())),
124
125            TypeKind::SliceView(inner)
126            | TypeKind::QueueView(inner)
127            | TypeKind::StackView(inner)
128            | TypeKind::SparseView(inner)
129            | TypeKind::DynamicLengthVecView(inner) => Some(TypeKind::SliceView(inner.clone())),
130
131            _ => None,
132        }
133    }
134
135    #[must_use]
136    pub fn strict_compatible_with_capacity(&self, other: &Self) -> bool {
137        match (&*self.kind, &*other.kind) {
138            (TypeKind::VecStorage(_, cap_a), TypeKind::VecStorage(_, cap_b)) => cap_a == cap_b,
139            (TypeKind::SparseStorage(_, cap_a), TypeKind::SparseStorage(_, cap_b)) => {
140                cap_a == cap_b
141            }
142            (TypeKind::QueueStorage(_, cap_a), TypeKind::QueueStorage(_, cap_b)) => cap_a == cap_b,
143            (TypeKind::StackStorage(_, cap_a), TypeKind::StackStorage(_, cap_b)) => cap_a == cap_b,
144            (TypeKind::MapStorage(_, _, cap_a), TypeKind::MapStorage(_, _, cap_b)) => {
145                cap_a == cap_b
146            }
147            (
148                TypeKind::GridStorage(_, rows_a, cols_a),
149                TypeKind::GridStorage(_, rows_b, cols_b),
150            ) => rows_a == rows_b && cols_a == cols_b,
151            // For all other types, default to regular compatibility
152            _ => self.id == other.id,
153        }
154    }
155}