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