1use std::cmp::min;
5
6use Type::*;
7
8use crate::value::r#type::Type;
9
10impl Type {
11 pub fn promote(left: Type, right: Type) -> Type {
12 if matches!(left, Any) || matches!(right, Any) {
13 return Any;
14 }
15
16 if matches!(left, Option(_)) || matches!(right, Option(_)) {
17 return left;
18 }
19
20 if left == Utf8 || right == Utf8 {
21 return Utf8;
22 }
23
24 if left == Boolean || right == Boolean {
25 return Boolean;
26 }
27
28 if left == Float8 || right == Float8 {
29 return Float8;
30 }
31
32 if left == Float4 || right == Float4 {
33 return Float8;
34 }
35
36 let signed_order = [Int1, Int2, Int4, Int8, Int16];
37 let unsigned_order = [Uint1, Uint2, Uint4, Uint8, Uint16];
38
39 let is_signed = |k: &Type| signed_order.contains(k);
40 let is_unsigned = |k: &Type| unsigned_order.contains(k);
41
42 let rank = |k: &Type| match k {
43 Int1 | Uint1 => 0,
44 Int2 | Uint2 => 1,
45 Int4 | Uint4 => 2,
46 Int8 | Uint8 => 3,
47 Int16 | Uint16 => 4,
48 _ => usize::MAX,
49 };
50
51 if is_signed(&left) && is_signed(&right) {
52 return signed_order[min(rank(&left).max(rank(&right)), 3) + 1].clone();
53 }
54
55 if is_unsigned(&left) && is_unsigned(&right) {
56 return unsigned_order[min(rank(&left).max(rank(&right)), 3) + 1].clone();
57 }
58
59 if (is_signed(&left) && is_unsigned(&right)) || (is_unsigned(&left) && is_signed(&right)) {
60 return match rank(&left).max(rank(&right)) + 1 {
61 0 => Int1,
62 1 => Int2,
63 2 => Int4,
64 3 => Int8,
65 4 => Int16,
66 _ => Int16,
67 };
68 }
69
70 left
71 }
72}
73
74#[cfg(test)]
75pub mod tests {
76 use Type::*;
77
78 use crate::value::r#type::Type;
79
80 #[test]
81 fn test_promote_bool() {
82 let cases = [
83 (Boolean, Boolean, Boolean),
84 (Boolean, Float4, Boolean),
85 (Boolean, Float8, Boolean),
86 (Boolean, Int1, Boolean),
87 (Boolean, Int2, Boolean),
88 (Boolean, Int4, Boolean),
89 (Boolean, Int8, Boolean),
90 (Boolean, Int16, Boolean),
91 (Boolean, Utf8, Utf8),
92 (Boolean, Uint1, Boolean),
93 (Boolean, Uint2, Boolean),
94 (Boolean, Uint4, Boolean),
95 (Boolean, Uint8, Boolean),
96 (Boolean, Uint16, Boolean),
97 ];
98 for (left, right, expected) in cases {
99 assert_eq!(Type::promote(left, right), expected);
100 }
101 }
102
103 #[test]
104 fn test_promote_float4() {
105 let cases = [
106 (Float4, Boolean, Boolean),
107 (Float4, Float4, Float8),
108 (Float4, Float8, Float8),
109 (Float4, Int1, Float8),
110 (Float4, Int2, Float8),
111 (Float4, Int4, Float8),
112 (Float4, Int8, Float8),
113 (Float4, Int16, Float8),
114 (Float4, Utf8, Utf8),
115 (Float4, Uint1, Float8),
116 (Float4, Uint2, Float8),
117 (Float4, Uint4, Float8),
118 (Float4, Uint8, Float8),
119 (Float4, Uint16, Float8),
120 ];
121 for (left, right, expected) in cases {
122 assert_eq!(Type::promote(left, right), expected);
123 }
124 }
125
126 #[test]
127 fn test_promote_float8() {
128 let cases = [
129 (Float8, Boolean, Boolean),
130 (Float8, Float4, Float8),
131 (Float8, Float8, Float8),
132 (Float8, Int1, Float8),
133 (Float8, Int2, Float8),
134 (Float8, Int4, Float8),
135 (Float8, Int8, Float8),
136 (Float8, Int16, Float8),
137 (Float8, Utf8, Utf8),
138 (Float8, Uint1, Float8),
139 (Float8, Uint2, Float8),
140 (Float8, Uint4, Float8),
141 (Float8, Uint8, Float8),
142 (Float8, Uint16, Float8),
143 ];
144 for (left, right, expected) in cases {
145 assert_eq!(Type::promote(left, right), expected);
146 }
147 }
148
149 #[test]
150 fn test_promote_int1() {
151 let cases = [
152 (Int1, Boolean, Boolean),
153 (Int1, Float4, Float8),
154 (Int1, Float8, Float8),
155 (Int1, Int1, Int2),
156 (Int1, Int2, Int4),
157 (Int1, Int4, Int8),
158 (Int1, Int8, Int16),
159 (Int1, Int16, Int16),
160 (Int1, Utf8, Utf8),
161 (Int1, Uint1, Int2),
162 (Int1, Uint2, Int4),
163 (Int1, Uint4, Int8),
164 (Int1, Uint8, Int16),
165 (Int1, Uint16, Int16),
166 ];
167 for (left, right, expected) in cases {
168 assert_eq!(Type::promote(left, right), expected);
169 }
170 }
171
172 #[test]
173 fn test_promote_int2() {
174 let cases = [
175 (Int2, Boolean, Boolean),
176 (Int2, Float4, Float8),
177 (Int2, Float8, Float8),
178 (Int2, Int1, Int4),
179 (Int2, Int2, Int4),
180 (Int2, Int4, Int8),
181 (Int2, Int8, Int16),
182 (Int2, Int16, Int16),
183 (Int2, Utf8, Utf8),
184 (Int2, Uint1, Int4),
185 (Int2, Uint2, Int4),
186 (Int2, Uint4, Int8),
187 (Int2, Uint8, Int16),
188 (Int2, Uint16, Int16),
189 ];
190 for (left, right, expected) in cases {
191 assert_eq!(Type::promote(left, right), expected);
192 }
193 }
194
195 #[test]
196 fn test_promote_int4() {
197 let cases = [
198 (Int4, Boolean, Boolean),
199 (Int4, Float4, Float8),
200 (Int4, Float8, Float8),
201 (Int4, Int1, Int8),
202 (Int4, Int2, Int8),
203 (Int4, Int4, Int8),
204 (Int4, Int8, Int16),
205 (Int4, Int16, Int16),
206 (Int4, Utf8, Utf8),
207 (Int4, Uint1, Int8),
208 (Int4, Uint2, Int8),
209 (Int4, Uint4, Int8),
210 (Int4, Uint8, Int16),
211 (Int4, Uint16, Int16),
212 ];
213 for (left, right, expected) in cases {
214 assert_eq!(Type::promote(left, right), expected);
215 }
216 }
217
218 #[test]
219 fn test_promote_int8() {
220 let cases = [
221 (Int8, Boolean, Boolean),
222 (Int8, Float4, Float8),
223 (Int8, Float8, Float8),
224 (Int8, Int1, Int16),
225 (Int8, Int2, Int16),
226 (Int8, Int4, Int16),
227 (Int8, Int8, Int16),
228 (Int8, Int16, Int16),
229 (Int8, Utf8, Utf8),
230 (Int8, Uint1, Int16),
231 (Int8, Uint2, Int16),
232 (Int8, Uint4, Int16),
233 (Int8, Uint8, Int16),
234 (Int8, Uint16, Int16),
235 ];
236 for (left, right, expected) in cases {
237 assert_eq!(Type::promote(left, right), expected);
238 }
239 }
240
241 #[test]
242 fn test_promote_int16() {
243 let cases = [
244 (Int16, Boolean, Boolean),
245 (Int16, Float4, Float8),
246 (Int16, Float8, Float8),
247 (Int16, Int1, Int16),
248 (Int16, Int2, Int16),
249 (Int16, Int4, Int16),
250 (Int16, Int8, Int16),
251 (Int16, Int16, Int16),
252 (Int16, Utf8, Utf8),
253 (Int16, Uint1, Int16),
254 (Int16, Uint2, Int16),
255 (Int16, Uint4, Int16),
256 (Int16, Uint8, Int16),
257 (Int16, Uint16, Int16),
258 ];
259 for (left, right, expected) in cases {
260 assert_eq!(Type::promote(left, right), expected);
261 }
262 }
263
264 #[test]
265 fn test_promote_string() {
266 let kinds = [
267 Boolean, Float4, Float8, Int1, Int2, Int4, Int8, Int16, Utf8, Uint1, Uint2, Uint4, Uint8,
268 Uint16,
269 ];
270 for ty in kinds {
271 assert_eq!(Type::promote(Utf8, ty), Utf8);
272 }
273 }
274
275 #[test]
276 fn test_promote_uint1() {
277 let cases = [
278 (Uint1, Boolean, Boolean),
279 (Uint1, Float4, Float8),
280 (Uint1, Float8, Float8),
281 (Uint1, Int1, Int2),
282 (Uint1, Int2, Int4),
283 (Uint1, Int4, Int8),
284 (Uint1, Int8, Int16),
285 (Uint1, Int16, Int16),
286 (Uint1, Utf8, Utf8),
287 (Uint1, Uint1, Uint2),
288 (Uint1, Uint2, Uint4),
289 (Uint1, Uint4, Uint8),
290 (Uint1, Uint8, Uint16),
291 (Uint1, Uint16, Uint16),
292 ];
293 for (left, right, expected) in cases {
294 assert_eq!(Type::promote(left, right), expected);
295 }
296 }
297
298 #[test]
299 fn test_promote_uint2() {
300 let cases = [
301 (Uint2, Boolean, Boolean),
302 (Uint2, Float4, Float8),
303 (Uint2, Float8, Float8),
304 (Uint2, Int1, Int4),
305 (Uint2, Int2, Int4),
306 (Uint2, Int4, Int8),
307 (Uint2, Int8, Int16),
308 (Uint2, Int16, Int16),
309 (Uint2, Utf8, Utf8),
310 (Uint2, Uint1, Uint4),
311 (Uint2, Uint2, Uint4),
312 (Uint2, Uint4, Uint8),
313 (Uint2, Uint8, Uint16),
314 (Uint2, Uint16, Uint16),
315 ];
316 for (left, right, expected) in cases {
317 assert_eq!(Type::promote(left, right), expected);
318 }
319 }
320
321 #[test]
322 fn test_promote_uint4() {
323 let cases = [
324 (Uint4, Boolean, Boolean),
325 (Uint4, Float4, Float8),
326 (Uint4, Float8, Float8),
327 (Uint4, Int1, Int8),
328 (Uint4, Int2, Int8),
329 (Uint4, Int4, Int8),
330 (Uint4, Int8, Int16),
331 (Uint4, Int16, Int16),
332 (Uint4, Utf8, Utf8),
333 (Uint4, Uint1, Uint8),
334 (Uint4, Uint2, Uint8),
335 (Uint4, Uint4, Uint8),
336 (Uint4, Uint8, Uint16),
337 (Uint4, Uint16, Uint16),
338 ];
339 for (left, right, expected) in cases {
340 assert_eq!(Type::promote(left, right), expected);
341 }
342 }
343
344 #[test]
345 fn test_promote_uint8() {
346 let cases = [
347 (Uint8, Boolean, Boolean),
348 (Uint8, Float4, Float8),
349 (Uint8, Float8, Float8),
350 (Uint8, Int1, Int16),
351 (Uint8, Int2, Int16),
352 (Uint8, Int4, Int16),
353 (Uint8, Int8, Int16),
354 (Uint8, Int16, Int16),
355 (Uint8, Utf8, Utf8),
356 (Uint8, Uint1, Uint16),
357 (Uint8, Uint2, Uint16),
358 (Uint8, Uint4, Uint16),
359 (Uint8, Uint8, Uint16),
360 (Uint8, Uint16, Uint16),
361 ];
362 for (left, right, expected) in cases {
363 assert_eq!(Type::promote(left, right), expected);
364 }
365 }
366
367 #[test]
368 fn test_promote_any_is_absorbing() {
369 let kinds = [
370 Boolean,
371 Float4,
372 Float8,
373 Int1,
374 Int2,
375 Int4,
376 Int8,
377 Int16,
378 Uint1,
379 Uint2,
380 Uint4,
381 Uint8,
382 Uint16,
383 Utf8,
384 Date,
385 DateTime,
386 Time,
387 Duration,
388 Uuid4,
389 Uuid7,
390 Blob,
391 IdentityId,
392 DictionaryId,
393 Int,
394 Uint,
395 Decimal,
396 Any,
397 ];
398 for ty in kinds {
399 assert_eq!(Type::promote(Any, ty.clone()), Any, "Any on left with {:?}", ty);
400 assert_eq!(Type::promote(ty.clone(), Any), Any, "Any on right with {:?}", ty);
401 }
402 assert_eq!(Type::promote(Any, Option(Box::new(Int4))), Any);
403 assert_eq!(Type::promote(Option(Box::new(Int4)), Any), Any);
404 }
405
406 #[test]
407 fn test_promote_uint16() {
408 let cases = [
409 (Uint16, Boolean, Boolean),
410 (Uint16, Float4, Float8),
411 (Uint16, Float8, Float8),
412 (Uint16, Int1, Int16),
413 (Uint16, Int2, Int16),
414 (Uint16, Int4, Int16),
415 (Uint16, Int8, Int16),
416 (Uint16, Int16, Int16),
417 (Uint16, Utf8, Utf8),
418 (Uint16, Uint1, Uint16),
419 (Uint16, Uint2, Uint16),
420 (Uint16, Uint4, Uint16),
421 (Uint16, Uint8, Uint16),
422 (Uint16, Uint16, Uint16),
423 ];
424 for (left, right, expected) in cases {
425 assert_eq!(Type::promote(left, right), expected);
426 }
427 }
428}