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