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