1use std::{
5 fmt::{Display, Formatter},
6 str::FromStr,
7};
8
9use serde::{Deserialize, Serialize};
10
11pub mod get;
12pub mod promote;
13
14use crate::value::Value;
15
16#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
18pub enum Type {
19 Boolean,
21 Float4,
23 Float8,
25 Int1,
27 Int2,
29 Int4,
31 Int8,
33 Int16,
35 Utf8,
37 Uint1,
39 Uint2,
41 Uint4,
43 Uint8,
45 Uint16,
47 Date,
49 DateTime,
51 Time,
53 Duration,
55 IdentityId,
57 Uuid4,
59 Uuid7,
61 Blob,
63 Int,
65 Uint,
67 Decimal,
69 Option(Box<Type>),
71 Any,
73 DictionaryId,
75}
76
77impl Type {
78 pub fn is_number(&self) -> bool {
79 match self {
80 Type::Option(inner) => inner.is_number(),
81 _ => matches!(
82 self,
83 Type::Float4
84 | Type::Float8 | Type::Int1 | Type::Int2
85 | Type::Int4 | Type::Int8 | Type::Int16
86 | Type::Uint1 | Type::Uint2 | Type::Uint4
87 | Type::Uint8 | Type::Uint16 | Type::Int
88 | Type::Uint | Type::Decimal
89 ),
90 }
91 }
92
93 pub fn is_bool(&self) -> bool {
94 match self {
95 Type::Option(inner) => inner.is_bool(),
96 _ => matches!(self, Type::Boolean),
97 }
98 }
99
100 pub fn is_signed_integer(&self) -> bool {
101 match self {
102 Type::Option(inner) => inner.is_signed_integer(),
103 _ => matches!(
104 self,
105 Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16 | Type::Int
106 ),
107 }
108 }
109
110 pub fn is_unsigned_integer(&self) -> bool {
111 match self {
112 Type::Option(inner) => inner.is_unsigned_integer(),
113 _ => matches!(
114 self,
115 Type::Uint1 | Type::Uint2 | Type::Uint4 | Type::Uint8 | Type::Uint16 | Type::Uint
116 ),
117 }
118 }
119
120 pub fn is_integer(&self) -> bool {
121 self.is_signed_integer() || self.is_unsigned_integer()
122 }
123
124 pub fn is_floating_point(&self) -> bool {
125 match self {
126 Type::Option(inner) => inner.is_floating_point(),
127 _ => matches!(self, Type::Float4 | Type::Float8),
128 }
129 }
130
131 pub fn is_utf8(&self) -> bool {
132 match self {
133 Type::Option(inner) => inner.is_utf8(),
134 _ => matches!(self, Type::Utf8),
135 }
136 }
137
138 pub fn is_temporal(&self) -> bool {
139 match self {
140 Type::Option(inner) => inner.is_temporal(),
141 _ => matches!(self, Type::Date | Type::DateTime | Type::Time | Type::Duration),
142 }
143 }
144
145 pub fn is_uuid(&self) -> bool {
146 match self {
147 Type::Option(inner) => inner.is_uuid(),
148 _ => matches!(self, Type::Uuid4 | Type::Uuid7),
149 }
150 }
151
152 pub fn is_blob(&self) -> bool {
153 match self {
154 Type::Option(inner) => inner.is_blob(),
155 _ => matches!(self, Type::Blob),
156 }
157 }
158
159 pub fn is_option(&self) -> bool {
160 matches!(self, Type::Option(_))
161 }
162
163 pub fn inner_type(&self) -> &Type {
165 match self {
166 Type::Option(inner) => inner,
167 other => other,
168 }
169 }
170}
171
172impl Type {
173 pub fn to_u8(&self) -> u8 {
174 match self {
175 Type::Option(inner) => 0x80 | inner.to_u8(),
176 Type::Float4 => 1,
177 Type::Float8 => 2,
178 Type::Int1 => 3,
179 Type::Int2 => 4,
180 Type::Int4 => 5,
181 Type::Int8 => 6,
182 Type::Int16 => 7,
183 Type::Utf8 => 8,
184 Type::Uint1 => 9,
185 Type::Uint2 => 10,
186 Type::Uint4 => 11,
187 Type::Uint8 => 12,
188 Type::Uint16 => 13,
189 Type::Boolean => 14,
190 Type::Date => 15,
191 Type::DateTime => 16,
192 Type::Time => 17,
193 Type::Duration => 18,
194 Type::IdentityId => 19,
195 Type::Uuid4 => 20,
196 Type::Uuid7 => 21,
197 Type::Blob => 22,
198 Type::Int => 23,
199 Type::Decimal {
200 ..
201 } => 24,
202 Type::Uint => 25,
203 Type::Any => 26,
204 Type::DictionaryId => 27,
205 }
206 }
207}
208
209impl Type {
210 pub fn from_u8(value: u8) -> Self {
211 if value & 0x80 != 0 {
212 return Type::Option(Box::new(Type::from_u8(value & 0x7F)));
213 }
214 match value {
215 1 => Type::Float4,
216 2 => Type::Float8,
217 3 => Type::Int1,
218 4 => Type::Int2,
219 5 => Type::Int4,
220 6 => Type::Int8,
221 7 => Type::Int16,
222 8 => Type::Utf8,
223 9 => Type::Uint1,
224 10 => Type::Uint2,
225 11 => Type::Uint4,
226 12 => Type::Uint8,
227 13 => Type::Uint16,
228 14 => Type::Boolean,
229 15 => Type::Date,
230 16 => Type::DateTime,
231 17 => Type::Time,
232 18 => Type::Duration,
233 19 => Type::IdentityId,
234 20 => Type::Uuid4,
235 21 => Type::Uuid7,
236 22 => Type::Blob,
237 23 => Type::Int,
238 24 => Type::Decimal,
239 25 => Type::Uint,
240 26 => Type::Any,
241 27 => Type::DictionaryId,
242 _ => unreachable!(),
243 }
244 }
245}
246
247impl Type {
248 pub fn size(&self) -> usize {
249 match self {
250 Type::Boolean => 1,
251 Type::Float4 => 4,
252 Type::Float8 => 8,
253 Type::Int1 => 1,
254 Type::Int2 => 2,
255 Type::Int4 => 4,
256 Type::Int8 => 8,
257 Type::Int16 => 16,
258 Type::Utf8 => 8, Type::Uint1 => 1,
260 Type::Uint2 => 2,
261 Type::Uint4 => 4,
262 Type::Uint8 => 8,
263 Type::Uint16 => 16,
264 Type::Date => 4,
265 Type::DateTime => 12, Type::Time => 8,
267 Type::Duration => 16, Type::IdentityId => 16, Type::Uuid4 => 16,
271 Type::Uuid7 => 16,
272 Type::Blob => 8, Type::Int => 16, Type::Uint => 16, Type::Decimal {
278 ..
279 } => 16, Type::Option(inner) => inner.size(), Type::Any => 8, Type::DictionaryId => 16, }
286 }
287
288 pub fn alignment(&self) -> usize {
289 match self {
290 Type::Boolean => 1,
291 Type::Float4 => 4,
292 Type::Float8 => 8,
293 Type::Int1 => 1,
294 Type::Int2 => 2,
295 Type::Int4 => 4,
296 Type::Int8 => 8,
297 Type::Int16 => 16,
298 Type::Utf8 => 4, Type::Uint1 => 1,
300 Type::Uint2 => 2,
301 Type::Uint4 => 4,
302 Type::Uint8 => 8,
303 Type::Uint16 => 16,
304 Type::Date => 4,
305 Type::DateTime => 8,
306 Type::Time => 8,
307 Type::Duration => 8,
308 Type::IdentityId => 8, Type::Uuid4 => 8,
310 Type::Uuid7 => 8,
311 Type::Blob => 4, Type::Int => 16, Type::Uint => 16, Type::Decimal {
317 ..
318 } => 16, Type::Option(inner) => inner.alignment(),
321 Type::Any => 8, Type::DictionaryId => 16,
323 }
324 }
325}
326
327impl Display for Type {
328 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
329 match self {
330 Type::Boolean => f.write_str("Boolean"),
331 Type::Float4 => f.write_str("Float4"),
332 Type::Float8 => f.write_str("Float8"),
333 Type::Int1 => f.write_str("Int1"),
334 Type::Int2 => f.write_str("Int2"),
335 Type::Int4 => f.write_str("Int4"),
336 Type::Int8 => f.write_str("Int8"),
337 Type::Int16 => f.write_str("Int16"),
338 Type::Utf8 => f.write_str("Utf8"),
339 Type::Uint1 => f.write_str("Uint1"),
340 Type::Uint2 => f.write_str("Uint2"),
341 Type::Uint4 => f.write_str("Uint4"),
342 Type::Uint8 => f.write_str("Uint8"),
343 Type::Uint16 => f.write_str("Uint16"),
344 Type::Date => f.write_str("Date"),
345 Type::DateTime => f.write_str("DateTime"),
346 Type::Time => f.write_str("Time"),
347 Type::Duration => f.write_str("Duration"),
348 Type::IdentityId => f.write_str("IdentityId"),
349 Type::Uuid4 => f.write_str("Uuid4"),
350 Type::Uuid7 => f.write_str("Uuid7"),
351 Type::Blob => f.write_str("Blob"),
352 Type::Int => f.write_str("Int"),
353 Type::Uint => f.write_str("Uint"),
354 Type::Decimal => f.write_str("Decimal"),
355 Type::Option(inner) => write!(f, "Option({inner})"),
356 Type::Any => f.write_str("Any"),
357 Type::DictionaryId => f.write_str("DictionaryId"),
358 }
359 }
360}
361
362impl From<&Value> for Type {
363 fn from(value: &Value) -> Self {
364 match value {
365 Value::None {
366 inner,
367 } => Type::Option(Box::new(inner.clone())),
368 Value::Boolean(_) => Type::Boolean,
369 Value::Float4(_) => Type::Float4,
370 Value::Float8(_) => Type::Float8,
371 Value::Int1(_) => Type::Int1,
372 Value::Int2(_) => Type::Int2,
373 Value::Int4(_) => Type::Int4,
374 Value::Int8(_) => Type::Int8,
375 Value::Int16(_) => Type::Int16,
376 Value::Utf8(_) => Type::Utf8,
377 Value::Uint1(_) => Type::Uint1,
378 Value::Uint2(_) => Type::Uint2,
379 Value::Uint4(_) => Type::Uint4,
380 Value::Uint8(_) => Type::Uint8,
381 Value::Uint16(_) => Type::Uint16,
382 Value::Date(_) => Type::Date,
383 Value::DateTime(_) => Type::DateTime,
384 Value::Time(_) => Type::Time,
385 Value::Duration(_) => Type::Duration,
386 Value::IdentityId(_) => Type::IdentityId,
387 Value::Uuid4(_) => Type::Uuid4,
388 Value::Uuid7(_) => Type::Uuid7,
389 Value::Blob(_) => Type::Blob,
390 Value::Int(_) => Type::Int,
391 Value::Uint(_) => Type::Uint,
392 Value::Decimal(_) => Type::Decimal,
393 Value::Any(_) => Type::Any,
394 Value::DictionaryId(_) => Type::DictionaryId,
395 Value::Type(t) => t.clone(),
396 }
397 }
398}
399
400impl FromStr for Type {
401 type Err = ();
402
403 fn from_str(s: &str) -> Result<Self, Self::Err> {
404 let upper = s.to_uppercase();
405 if upper.starts_with("OPTION<") && upper.ends_with('>') {
407 let inner_str = &s[7..s.len() - 1]; let inner = Type::from_str(inner_str)?;
409 return Ok(Type::Option(Box::new(inner)));
410 }
411 match upper.as_str() {
412 "BOOL" | "BOOLEAN" => Ok(Type::Boolean),
413 "FLOAT4" => Ok(Type::Float4),
414 "FLOAT8" => Ok(Type::Float8),
415 "INT1" => Ok(Type::Int1),
416 "INT2" => Ok(Type::Int2),
417 "INT4" => Ok(Type::Int4),
418 "INT8" => Ok(Type::Int8),
419 "INT16" => Ok(Type::Int16),
420 "UTF8" | "TEXT" => Ok(Type::Utf8),
421 "UINT1" => Ok(Type::Uint1),
422 "UINT2" => Ok(Type::Uint2),
423 "UINT4" => Ok(Type::Uint4),
424 "UINT8" => Ok(Type::Uint8),
425 "UINT16" => Ok(Type::Uint16),
426 "DATE" => Ok(Type::Date),
427 "DATETIME" => Ok(Type::DateTime),
428 "TIME" => Ok(Type::Time),
429 "DURATION" | "INTERVAL" => Ok(Type::Duration),
430 "IDENTITYID" | "IDENTITY_ID" => Ok(Type::IdentityId),
431 "UUID4" => Ok(Type::Uuid4),
432 "UUID7" => Ok(Type::Uuid7),
433 "BLOB" => Ok(Type::Blob),
434 "INT" => Ok(Type::Int),
435 "UINT" => Ok(Type::Uint),
436 "DECIMAL" => Ok(Type::Decimal),
437 "ANY" => Ok(Type::Any),
438 "DICTIONARYID" | "DICTIONARY_ID" => Ok(Type::DictionaryId),
439 _ => Err(()),
440 }
441 }
442}