reifydb_type/value/type/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::{
5	fmt::{Display, Formatter},
6	str::FromStr,
7};
8
9use serde::{Deserialize, Serialize};
10
11mod get;
12mod promote;
13
14pub use get::GetType;
15
16use crate::Value;
17
18/// All possible RQL data types
19#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
20pub enum Type {
21	/// A boolean: true or false.
22	Boolean,
23	/// A 4-byte floating point
24	Float4,
25	/// An 8-byte floating point
26	Float8,
27	/// A 1-byte signed integer
28	Int1,
29	/// A 2-byte signed integer
30	Int2,
31	/// A 4-byte signed integer
32	Int4,
33	/// An 8-byte signed integer
34	Int8,
35	/// A 16-byte signed integer
36	Int16,
37	/// A UTF-8 encoded text.
38	Utf8,
39	/// A 1-byte unsigned integer
40	Uint1,
41	/// A 2-byte unsigned integer
42	Uint2,
43	/// A 4-byte unsigned integer
44	Uint4,
45	/// A 8-byte unsigned integer
46	Uint8,
47	/// A 16-byte unsigned integer
48	Uint16,
49	/// A date value (year, month, day)
50	Date,
51	/// A date and time value with nanosecond precision in SVTC
52	DateTime,
53	/// A time value (hour, minute, second, nanosecond)
54	Time,
55	/// A duration representing a duration
56	Duration,
57	/// A encoded identifier (8-byte unsigned integer)
58	RowNumber,
59	/// An identity identifier (UUID v7)
60	IdentityId,
61	/// A UUID version 4 (random)
62	Uuid4,
63	/// A UUID version 7 (timestamp-based)
64	Uuid7,
65	/// A binary large object (BLOB)
66	Blob,
67	/// An arbitrary-precision signed integer
68	Int,
69	/// An arbitrary-precision unsigned integer
70	Uint,
71	/// An arbitrary-precision decimal with precision and scale
72	Decimal,
73	/// Value is not defined (think null in common programming languages)
74	Undefined,
75	/// A container that can hold any value type
76	Any,
77}
78
79impl Type {
80	pub fn is_number(&self) -> bool {
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	pub fn is_bool(&self) -> bool {
93		matches!(self, Type::Boolean)
94	}
95
96	pub fn is_signed_integer(&self) -> bool {
97		matches!(self, Type::Int1 | Type::Int2 | Type::Int4 | Type::Int8 | Type::Int16 | Type::Int)
98	}
99
100	pub fn is_unsigned_integer(&self) -> bool {
101		matches!(self, Type::Uint1 | Type::Uint2 | Type::Uint4 | Type::Uint8 | Type::Uint16 | Type::Uint)
102	}
103
104	pub fn is_integer(&self) -> bool {
105		self.is_signed_integer() || self.is_unsigned_integer()
106	}
107
108	pub fn is_floating_point(&self) -> bool {
109		matches!(self, Type::Float4 | Type::Float8)
110	}
111
112	pub fn is_utf8(&self) -> bool {
113		matches!(self, Type::Utf8)
114	}
115
116	pub fn is_temporal(&self) -> bool {
117		matches!(self, Type::Date | Type::DateTime | Type::Time | Type::Duration)
118	}
119
120	pub fn is_uuid(&self) -> bool {
121		matches!(self, Type::Uuid4 | Type::Uuid7)
122	}
123
124	pub fn is_blob(&self) -> bool {
125		matches!(self, Type::Blob)
126	}
127}
128
129impl Type {
130	pub fn to_u8(&self) -> u8 {
131		match self {
132			Type::Undefined => 0,
133			Type::Float4 => 1,
134			Type::Float8 => 2,
135			Type::Int1 => 3,
136			Type::Int2 => 4,
137			Type::Int4 => 5,
138			Type::Int8 => 6,
139			Type::Int16 => 7,
140			Type::Utf8 => 8,
141			Type::Uint1 => 9,
142			Type::Uint2 => 10,
143			Type::Uint4 => 11,
144			Type::Uint8 => 12,
145			Type::Uint16 => 13,
146			Type::Boolean => 14,
147			Type::Date => 15,
148			Type::DateTime => 16,
149			Type::Time => 17,
150			Type::Duration => 18,
151			Type::RowNumber => 19,
152			Type::Uuid4 => 20,
153			Type::Uuid7 => 21,
154			Type::Blob => 22,
155			Type::IdentityId => 23,
156			Type::Int => 24,
157			Type::Decimal {
158				..
159			} => 25,
160			Type::Uint => 26,
161			Type::Any => 27,
162		}
163	}
164}
165
166impl Type {
167	pub fn from_u8(value: u8) -> Self {
168		match value {
169			0 => Type::Undefined,
170			1 => Type::Float4,
171			2 => Type::Float8,
172			3 => Type::Int1,
173			4 => Type::Int2,
174			5 => Type::Int4,
175			6 => Type::Int8,
176			7 => Type::Int16,
177			8 => Type::Utf8,
178			9 => Type::Uint1,
179			10 => Type::Uint2,
180			11 => Type::Uint4,
181			12 => Type::Uint8,
182			13 => Type::Uint16,
183			14 => Type::Boolean,
184			15 => Type::Date,
185			16 => Type::DateTime,
186			17 => Type::Time,
187			18 => Type::Duration,
188			19 => Type::RowNumber,
189			20 => Type::Uuid4,
190			21 => Type::Uuid7,
191			22 => Type::Blob,
192			23 => Type::IdentityId,
193			24 => Type::Int,
194			25 => Type::Decimal,
195			26 => Type::Uint,
196			27 => Type::Any,
197			_ => unreachable!(),
198		}
199	}
200}
201
202impl Type {
203	pub fn size(&self) -> usize {
204		match self {
205			Type::Boolean => 1,
206			Type::Float4 => 4,
207			Type::Float8 => 8,
208			Type::Int1 => 1,
209			Type::Int2 => 2,
210			Type::Int4 => 4,
211			Type::Int8 => 8,
212			Type::Int16 => 16,
213			Type::Utf8 => 8, // offset: u32 + length: u32
214			Type::Uint1 => 1,
215			Type::Uint2 => 2,
216			Type::Uint4 => 4,
217			Type::Uint8 => 8,
218			Type::Uint16 => 16,
219			Type::Date => 4,
220			Type::DateTime => 12, // seconds: i64 + nanos: u32
221			Type::Time => 8,
222			Type::Duration => 16, // months: i32 + days: i32 +
223			// nanos: i64
224			Type::RowNumber => 8,
225			Type::IdentityId => 16, // UUID v7 is 16 bytes
226			Type::Uuid4 => 16,
227			Type::Uuid7 => 16,
228			Type::Blob => 8, // offset: u32 + length: u32
229			Type::Int => 16, // i128 inline or dynamic
230			// storage with offset + length
231			Type::Uint => 16, // u128 inline or dynamic
232			// storage with offset + length
233			Type::Decimal {
234				..
235			} => 16, // i128 inline or dynamic
236			// storage with offset + length
237			Type::Undefined => 0,
238			Type::Any => 8, // pointer size on 64-bit systems
239		}
240	}
241
242	pub fn alignment(&self) -> usize {
243		match self {
244			Type::Boolean => 1,
245			Type::Float4 => 4,
246			Type::Float8 => 8,
247			Type::Int1 => 1,
248			Type::Int2 => 2,
249			Type::Int4 => 4,
250			Type::Int8 => 8,
251			Type::Int16 => 16,
252			Type::Utf8 => 4, // u32 alignment
253			Type::Uint1 => 1,
254			Type::Uint2 => 2,
255			Type::Uint4 => 4,
256			Type::Uint8 => 8,
257			Type::Uint16 => 16,
258			Type::Date => 4,
259			Type::DateTime => 8,
260			Type::Time => 8,
261			Type::Duration => 8,
262			Type::RowNumber => 8,
263			Type::IdentityId => 8, // Same alignment as UUID
264			Type::Uuid4 => 8,
265			Type::Uuid7 => 8,
266			Type::Blob => 4, // u32 alignment
267			Type::Int => 16, // i128 alignment for
268			// inline storage
269			Type::Uint => 16, // u128 alignment for
270			// inline storage
271			Type::Decimal {
272				..
273			} => 16, // i128 alignment for
274			// inline storage
275			Type::Undefined => 0,
276			Type::Any => 8, // pointer alignment
277		}
278	}
279}
280
281impl Display for Type {
282	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
283		match self {
284			Type::Boolean => f.write_str("Boolean"),
285			Type::Float4 => f.write_str("Float4"),
286			Type::Float8 => f.write_str("Float8"),
287			Type::Int1 => f.write_str("Int1"),
288			Type::Int2 => f.write_str("Int2"),
289			Type::Int4 => f.write_str("Int4"),
290			Type::Int8 => f.write_str("Int8"),
291			Type::Int16 => f.write_str("Int16"),
292			Type::Utf8 => f.write_str("Utf8"),
293			Type::Uint1 => f.write_str("Uint1"),
294			Type::Uint2 => f.write_str("Uint2"),
295			Type::Uint4 => f.write_str("Uint4"),
296			Type::Uint8 => f.write_str("Uint8"),
297			Type::Uint16 => f.write_str("Uint16"),
298			Type::Date => f.write_str("Date"),
299			Type::DateTime => f.write_str("DateTime"),
300			Type::Time => f.write_str("Time"),
301			Type::Duration => f.write_str("Duration"),
302			Type::RowNumber => f.write_str("RowNumber"),
303			Type::IdentityId => f.write_str("IdentityId"),
304			Type::Uuid4 => f.write_str("Uuid4"),
305			Type::Uuid7 => f.write_str("Uuid7"),
306			Type::Blob => f.write_str("Blob"),
307			Type::Int => f.write_str("Int"),
308			Type::Uint => f.write_str("Uint"),
309			Type::Decimal => f.write_str("Decimal"),
310			Type::Undefined => f.write_str("Undefined"),
311			Type::Any => f.write_str("Any"),
312		}
313	}
314}
315
316impl From<&Value> for Type {
317	fn from(value: &Value) -> Self {
318		match value {
319			Value::Undefined => Type::Undefined,
320			Value::Boolean(_) => Type::Boolean,
321			Value::Float4(_) => Type::Float4,
322			Value::Float8(_) => Type::Float8,
323			Value::Int1(_) => Type::Int1,
324			Value::Int2(_) => Type::Int2,
325			Value::Int4(_) => Type::Int4,
326			Value::Int8(_) => Type::Int8,
327			Value::Int16(_) => Type::Int16,
328			Value::Utf8(_) => Type::Utf8,
329			Value::Uint1(_) => Type::Uint1,
330			Value::Uint2(_) => Type::Uint2,
331			Value::Uint4(_) => Type::Uint4,
332			Value::Uint8(_) => Type::Uint8,
333			Value::Uint16(_) => Type::Uint16,
334			Value::Date(_) => Type::Date,
335			Value::DateTime(_) => Type::DateTime,
336			Value::Time(_) => Type::Time,
337			Value::Duration(_) => Type::Duration,
338			Value::RowNumber(_) => Type::RowNumber,
339			Value::IdentityId(_) => Type::IdentityId,
340			Value::Uuid4(_) => Type::Uuid4,
341			Value::Uuid7(_) => Type::Uuid7,
342			Value::Blob(_) => Type::Blob,
343			Value::Int(_) => Type::Int,
344			Value::Uint(_) => Type::Uint,
345			Value::Decimal(_) => Type::Decimal,
346			Value::Any(_) => Type::Any,
347		}
348	}
349}
350
351impl FromStr for Type {
352	type Err = ();
353
354	fn from_str(s: &str) -> Result<Self, Self::Err> {
355		match s.to_uppercase().as_str() {
356			"BOOL" | "BOOLEAN" => Ok(Type::Boolean),
357			"FLOAT4" => Ok(Type::Float4),
358			"FLOAT8" => Ok(Type::Float8),
359			"INT1" => Ok(Type::Int1),
360			"INT2" => Ok(Type::Int2),
361			"INT4" => Ok(Type::Int4),
362			"INT8" => Ok(Type::Int8),
363			"INT16" => Ok(Type::Int16),
364			"UTF8" | "TEXT" => Ok(Type::Utf8),
365			"UINT1" => Ok(Type::Uint1),
366			"UINT2" => Ok(Type::Uint2),
367			"UINT4" => Ok(Type::Uint4),
368			"UINT8" => Ok(Type::Uint8),
369			"UINT16" => Ok(Type::Uint16),
370			"DATE" => Ok(Type::Date),
371			"DATETIME" => Ok(Type::DateTime),
372			"TIME" => Ok(Type::Time),
373			"DURATION" | "INTERVAL" => Ok(Type::Duration),
374			"ROWNUMBER" | "ROWID" => Ok(Type::RowNumber),
375			"IDENTITYID" | "IDENTITY_ID" => Ok(Type::IdentityId),
376			"UUID4" => Ok(Type::Uuid4),
377			"UUID7" => Ok(Type::Uuid7),
378			"BLOB" => Ok(Type::Blob),
379			"INT" => Ok(Type::Int),
380			"UINT" => Ok(Type::Uint),
381			"DECIMAL" => Ok(Type::Decimal),
382			"UNDEFINED" => Ok(Type::Undefined),
383			"ANY" => Ok(Type::Any),
384			_ => Err(()),
385		}
386	}
387}