1use std::{
5 fmt::{Display, Formatter},
6 str::FromStr,
7};
8
9use serde::{Deserialize, Serialize};
10
11pub mod get;
12pub mod input_types;
13pub mod promote;
14pub mod super_type;
15
16use std::fmt;
17
18use crate::value::Value;
19
20#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
22pub enum Type {
23 Boolean,
25 Float4,
27 Float8,
29 Int1,
31 Int2,
33 Int4,
35 Int8,
37 Int16,
39 Utf8,
41 Uint1,
43 Uint2,
45 Uint4,
47 Uint8,
49 Uint16,
51 Date,
53 DateTime,
55 Time,
57 Duration,
59 IdentityId,
61 Uuid4,
63 Uuid7,
65 Blob,
67 Int,
69 Uint,
71 Decimal,
73 Option(Box<Type>),
75 Any,
77 DictionaryId,
79 List(Box<Type>),
81 Record(Vec<(String, Type)>),
83 Tuple(Vec<Type>),
85}
86
87impl Type {
88 pub fn list_of(ty: Type) -> Self {
89 Type::List(Box::new(ty))
90 }
91
92 pub fn is_number(&self) -> bool {
93 match self {
94 Type::Option(inner) => inner.is_number(),
95 _ => matches!(
96 self,
97 Type::Float4
98 | Type::Float8 | Type::Int1 | Type::Int2
99 | Type::Int4 | Type::Int8 | Type::Int16
100 | Type::Uint1 | Type::Uint2 | Type::Uint4
101 | Type::Uint8 | Type::Uint16 | Type::Int
102 | Type::Uint | Type::Decimal
103 ),
104 }
105 }
106
107 pub fn is_bool(&self) -> bool {
108 match self {
109 Type::Option(inner) => inner.is_bool(),
110 _ => matches!(self, Type::Boolean),
111 }
112 }
113
114 pub fn is_signed_integer(&self) -> bool {
115 match self {
116 Type::Option(inner) => inner.is_signed_integer(),
117 _ => matches!(
118 self,
119 Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16 | Type::Int
120 ),
121 }
122 }
123
124 pub fn is_unsigned_integer(&self) -> bool {
125 match self {
126 Type::Option(inner) => inner.is_unsigned_integer(),
127 _ => matches!(
128 self,
129 Type::Uint1 | Type::Uint2 | Type::Uint4 | Type::Uint8 | Type::Uint16 | Type::Uint
130 ),
131 }
132 }
133
134 pub fn is_integer(&self) -> bool {
135 self.is_signed_integer() || self.is_unsigned_integer()
136 }
137
138 pub fn is_floating_point(&self) -> bool {
139 match self {
140 Type::Option(inner) => inner.is_floating_point(),
141 _ => matches!(self, Type::Float4 | Type::Float8),
142 }
143 }
144
145 pub fn is_utf8(&self) -> bool {
146 match self {
147 Type::Option(inner) => inner.is_utf8(),
148 _ => matches!(self, Type::Utf8),
149 }
150 }
151
152 pub fn is_temporal(&self) -> bool {
153 match self {
154 Type::Option(inner) => inner.is_temporal(),
155 _ => matches!(self, Type::Date | Type::DateTime | Type::Time | Type::Duration),
156 }
157 }
158
159 pub fn is_uuid(&self) -> bool {
160 match self {
161 Type::Option(inner) => inner.is_uuid(),
162 _ => matches!(self, Type::Uuid4 | Type::Uuid7),
163 }
164 }
165
166 pub fn is_blob(&self) -> bool {
167 match self {
168 Type::Option(inner) => inner.is_blob(),
169 _ => matches!(self, Type::Blob),
170 }
171 }
172
173 pub fn is_option(&self) -> bool {
174 matches!(self, Type::Option(_))
175 }
176
177 pub fn inner_type(&self) -> &Type {
179 match self {
180 Type::Option(inner) => inner,
181 other => other,
182 }
183 }
184}
185
186impl Type {
187 pub fn to_u8(&self) -> u8 {
188 match self {
189 Type::Option(inner) => 0x80 | inner.to_u8(),
190 Type::Float4 => 1,
191 Type::Float8 => 2,
192 Type::Int1 => 3,
193 Type::Int2 => 4,
194 Type::Int4 => 5,
195 Type::Int8 => 6,
196 Type::Int16 => 7,
197 Type::Utf8 => 8,
198 Type::Uint1 => 9,
199 Type::Uint2 => 10,
200 Type::Uint4 => 11,
201 Type::Uint8 => 12,
202 Type::Uint16 => 13,
203 Type::Boolean => 14,
204 Type::Date => 15,
205 Type::DateTime => 16,
206 Type::Time => 17,
207 Type::Duration => 18,
208 Type::IdentityId => 19,
209 Type::Uuid4 => 20,
210 Type::Uuid7 => 21,
211 Type::Blob => 22,
212 Type::Int => 23,
213 Type::Decimal => 24,
214 Type::Uint => 25,
215 Type::Any => 26,
216 Type::DictionaryId => 27,
217 Type::List(_) => 28,
218 Type::Record(_) => 29,
219 Type::Tuple(_) => 30,
220 }
221 }
222}
223
224impl Type {
225 pub fn from_u8(value: u8) -> Self {
226 if value & 0x80 != 0 {
227 return Type::Option(Box::new(Type::from_u8(value & 0x7F)));
228 }
229 match value {
230 1 => Type::Float4,
231 2 => Type::Float8,
232 3 => Type::Int1,
233 4 => Type::Int2,
234 5 => Type::Int4,
235 6 => Type::Int8,
236 7 => Type::Int16,
237 8 => Type::Utf8,
238 9 => Type::Uint1,
239 10 => Type::Uint2,
240 11 => Type::Uint4,
241 12 => Type::Uint8,
242 13 => Type::Uint16,
243 14 => Type::Boolean,
244 15 => Type::Date,
245 16 => Type::DateTime,
246 17 => Type::Time,
247 18 => Type::Duration,
248 19 => Type::IdentityId,
249 20 => Type::Uuid4,
250 21 => Type::Uuid7,
251 22 => Type::Blob,
252 23 => Type::Int,
253 24 => Type::Decimal,
254 25 => Type::Uint,
255 26 => Type::Any,
256 27 => Type::DictionaryId,
257 28 => Type::list_of(Type::Any),
258 29 => Type::Record(Vec::new()),
259 30 => Type::Tuple(Vec::new()),
260 _ => unreachable!(),
261 }
262 }
263}
264
265impl Type {
266 pub fn size(&self) -> usize {
267 match self {
268 Type::Boolean => 1,
269 Type::Float4 => 4,
270 Type::Float8 => 8,
271 Type::Int1 => 1,
272 Type::Int2 => 2,
273 Type::Int4 => 4,
274 Type::Int8 => 8,
275 Type::Int16 => 16,
276 Type::Utf8 => 8, Type::Uint1 => 1,
278 Type::Uint2 => 2,
279 Type::Uint4 => 4,
280 Type::Uint8 => 8,
281 Type::Uint16 => 16,
282 Type::Date => 4,
283 Type::DateTime => 8, Type::Time => 8,
285 Type::Duration => 16, Type::IdentityId => 16, Type::Uuid4 => 16,
288 Type::Uuid7 => 16,
289 Type::Blob => 8, Type::Int => 16, Type::Uint => 16, Type::Decimal => 16, Type::Option(inner) => inner.size(), Type::Any => 8, Type::List(_) => 8, Type::Record(_) => 8, Type::Tuple(_) => 8, Type::DictionaryId => 16, }
304 }
305
306 pub fn alignment(&self) -> usize {
307 match self {
308 Type::Boolean => 1,
309 Type::Float4 => 4,
310 Type::Float8 => 8,
311 Type::Int1 => 1,
312 Type::Int2 => 2,
313 Type::Int4 => 4,
314 Type::Int8 => 8,
315 Type::Int16 => 16,
316 Type::Utf8 => 4, Type::Uint1 => 1,
318 Type::Uint2 => 2,
319 Type::Uint4 => 4,
320 Type::Uint8 => 8,
321 Type::Uint16 => 16,
322 Type::Date => 4,
323 Type::DateTime => 8,
324 Type::Time => 8,
325 Type::Duration => 8,
326 Type::IdentityId => 8, Type::Uuid4 => 8,
328 Type::Uuid7 => 8,
329 Type::Blob => 4, Type::Int => 16, Type::Uint => 16, Type::Decimal => 16, Type::Option(inner) => inner.alignment(),
337 Type::Any => 8, Type::DictionaryId => 16,
339 Type::List(_) => 8, Type::Record(_) => 8, Type::Tuple(_) => 8, }
343 }
344}
345
346impl Display for Type {
347 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
348 match self {
349 Type::Boolean => f.write_str("Boolean"),
350 Type::Float4 => f.write_str("Float4"),
351 Type::Float8 => f.write_str("Float8"),
352 Type::Int1 => f.write_str("Int1"),
353 Type::Int2 => f.write_str("Int2"),
354 Type::Int4 => f.write_str("Int4"),
355 Type::Int8 => f.write_str("Int8"),
356 Type::Int16 => f.write_str("Int16"),
357 Type::Utf8 => f.write_str("Utf8"),
358 Type::Uint1 => f.write_str("Uint1"),
359 Type::Uint2 => f.write_str("Uint2"),
360 Type::Uint4 => f.write_str("Uint4"),
361 Type::Uint8 => f.write_str("Uint8"),
362 Type::Uint16 => f.write_str("Uint16"),
363 Type::Date => f.write_str("Date"),
364 Type::DateTime => f.write_str("DateTime"),
365 Type::Time => f.write_str("Time"),
366 Type::Duration => f.write_str("Duration"),
367 Type::IdentityId => f.write_str("IdentityId"),
368 Type::Uuid4 => f.write_str("Uuid4"),
369 Type::Uuid7 => f.write_str("Uuid7"),
370 Type::Blob => f.write_str("Blob"),
371 Type::Int => f.write_str("Int"),
372 Type::Uint => f.write_str("Uint"),
373 Type::Decimal => f.write_str("Decimal"),
374 Type::Option(inner) => write!(f, "Option({inner})"),
375 Type::Any => f.write_str("Any"),
376 Type::DictionaryId => f.write_str("DictionaryId"),
377 Type::List(inner) => write!(f, "List({inner})"),
378 Type::Record(fields) => {
379 f.write_str("Record(")?;
380 for (i, (name, ty)) in fields.iter().enumerate() {
381 if i > 0 {
382 f.write_str(", ")?;
383 }
384 write!(f, "{}: {}", name, ty)?;
385 }
386 f.write_str(")")
387 }
388 Type::Tuple(types) => {
389 f.write_str("Tuple(")?;
390 for (i, ty) in types.iter().enumerate() {
391 if i > 0 {
392 f.write_str(", ")?;
393 }
394 write!(f, "{}", ty)?;
395 }
396 f.write_str(")")
397 }
398 }
399 }
400}
401
402impl From<&Value> for Type {
403 fn from(value: &Value) -> Self {
404 match value {
405 Value::None {
406 inner,
407 } => Type::Option(Box::new(inner.clone())),
408 Value::Boolean(_) => Type::Boolean,
409 Value::Float4(_) => Type::Float4,
410 Value::Float8(_) => Type::Float8,
411 Value::Int1(_) => Type::Int1,
412 Value::Int2(_) => Type::Int2,
413 Value::Int4(_) => Type::Int4,
414 Value::Int8(_) => Type::Int8,
415 Value::Int16(_) => Type::Int16,
416 Value::Utf8(_) => Type::Utf8,
417 Value::Uint1(_) => Type::Uint1,
418 Value::Uint2(_) => Type::Uint2,
419 Value::Uint4(_) => Type::Uint4,
420 Value::Uint8(_) => Type::Uint8,
421 Value::Uint16(_) => Type::Uint16,
422 Value::Date(_) => Type::Date,
423 Value::DateTime(_) => Type::DateTime,
424 Value::Time(_) => Type::Time,
425 Value::Duration(_) => Type::Duration,
426 Value::IdentityId(_) => Type::IdentityId,
427 Value::Uuid4(_) => Type::Uuid4,
428 Value::Uuid7(_) => Type::Uuid7,
429 Value::Blob(_) => Type::Blob,
430 Value::Int(_) => Type::Int,
431 Value::Uint(_) => Type::Uint,
432 Value::Decimal(_) => Type::Decimal,
433 Value::Any(_) => Type::Any,
434 Value::DictionaryId(_) => Type::DictionaryId,
435 Value::Type(t) => t.clone(),
436 Value::List(items) => {
437 let element_type = items.first().map(Type::from).unwrap_or(Type::Any);
438 Type::list_of(element_type)
439 }
440 Value::Record(fields) => {
441 Type::Record(fields.iter().map(|(k, v)| (k.clone(), Type::from(v))).collect())
442 }
443 Value::Tuple(items) => Type::Tuple(items.iter().map(Type::from).collect()),
444 }
445 }
446}
447
448impl FromStr for Type {
449 type Err = ();
450
451 fn from_str(s: &str) -> Result<Self, Self::Err> {
452 let upper = s.to_uppercase();
453 if upper.starts_with("OPTION<") && upper.ends_with('>') {
455 let inner_str = &s[7..s.len() - 1]; let inner = Type::from_str(inner_str)?;
457 return Ok(Type::Option(Box::new(inner)));
458 }
459 match upper.as_str() {
460 "BOOL" | "BOOLEAN" => Ok(Type::Boolean),
461 "FLOAT4" => Ok(Type::Float4),
462 "FLOAT8" => Ok(Type::Float8),
463 "INT1" => Ok(Type::Int1),
464 "INT2" => Ok(Type::Int2),
465 "INT4" => Ok(Type::Int4),
466 "INT8" => Ok(Type::Int8),
467 "INT16" => Ok(Type::Int16),
468 "UTF8" | "TEXT" => Ok(Type::Utf8),
469 "UINT1" => Ok(Type::Uint1),
470 "UINT2" => Ok(Type::Uint2),
471 "UINT4" => Ok(Type::Uint4),
472 "UINT8" => Ok(Type::Uint8),
473 "UINT16" => Ok(Type::Uint16),
474 "DATE" => Ok(Type::Date),
475 "DATETIME" => Ok(Type::DateTime),
476 "TIME" => Ok(Type::Time),
477 "DURATION" | "INTERVAL" => Ok(Type::Duration),
478 "IDENTITYID" | "IDENTITY_ID" => Ok(Type::IdentityId),
479 "UUID4" => Ok(Type::Uuid4),
480 "UUID7" => Ok(Type::Uuid7),
481 "BLOB" => Ok(Type::Blob),
482 "INT" => Ok(Type::Int),
483 "UINT" => Ok(Type::Uint),
484 "DECIMAL" => Ok(Type::Decimal),
485 "ANY" => Ok(Type::Any),
486 "DICTIONARYID" | "DICTIONARY_ID" => Ok(Type::DictionaryId),
487 _ => Err(()),
488 }
489 }
490}