Skip to main content

reifydb_type/value/
mod.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2025 ReifyDB
3
4use std::{
5	cmp::Ordering,
6	fmt::{Display, Formatter},
7};
8
9use serde::{Deserialize, Serialize};
10
11pub mod as_string;
12pub mod blob;
13pub mod boolean;
14pub mod constraint;
15pub mod container;
16pub mod date;
17pub mod datetime;
18pub mod decimal;
19pub mod dictionary;
20pub mod duration;
21pub mod frame;
22pub mod identity;
23pub mod int;
24pub mod into;
25pub mod is;
26pub mod number;
27pub mod ordered_f32;
28pub mod ordered_f64;
29pub mod row_number;
30pub mod sumtype;
31pub mod temporal;
32pub mod time;
33pub mod try_from;
34pub mod r#type;
35pub mod uint;
36pub mod uuid;
37
38use std::{fmt, hash, mem};
39
40use blob::Blob;
41use date::Date;
42use datetime::DateTime;
43use decimal::Decimal;
44use dictionary::DictionaryEntryId;
45use duration::Duration;
46use identity::IdentityId;
47use int::Int;
48use ordered_f32::OrderedF32;
49use ordered_f64::OrderedF64;
50use time::Time;
51use r#type::Type;
52use uint::Uint;
53use uuid::{Uuid4, Uuid7};
54
55/// A RQL value, represented as a native Rust type.
56#[derive(Clone, Debug, Serialize, Deserialize)]
57pub enum Value {
58	/// Value is none (think null in common programming languages)
59	None {
60		#[serde(skip, default = "default_none_inner")]
61		inner: Type,
62	},
63	/// A boolean: true or false.
64	Boolean(bool),
65	/// A 4-byte floating point
66	Float4(OrderedF32),
67	/// An 8-byte floating point
68	Float8(OrderedF64),
69	/// A 1-byte signed integer
70	Int1(i8),
71	/// A 2-byte signed integer
72	Int2(i16),
73	/// A 4-byte signed integer
74	Int4(i32),
75	/// An 8-byte signed integer
76	Int8(i64),
77	/// A 16-byte signed integer
78	Int16(i128),
79	/// A UTF-8 encoded text. Maximum 255 bytes
80	Utf8(String),
81	/// A 1-byte unsigned integer
82	Uint1(u8),
83	/// A 2-byte unsigned integer
84	Uint2(u16),
85	/// A 4-byte unsigned integer
86	Uint4(u32),
87	/// A 8-byte unsigned integer
88	Uint8(u64),
89	/// A 16-byte unsigned integer
90	Uint16(u128),
91	/// A date value (year, month, day)
92	Date(Date),
93	/// A date and time value with nanosecond precision in SVTC
94	DateTime(DateTime),
95	/// A time value (hour, minute, second, nanosecond)
96	Time(Time),
97	/// A duration representing a duration
98	Duration(Duration),
99	/// An identity identifier (UUID v7)
100	IdentityId(IdentityId),
101	/// A UUID version 4 (random)
102	Uuid4(Uuid4),
103	/// A UUID version 7 (timestamp-based)
104	Uuid7(Uuid7),
105	/// A binary large object (BLOB)
106	Blob(Blob),
107	/// An arbitrary-precision signed integer
108	Int(Int),
109	/// An arbitrary-precision unsigned integer
110	Uint(Uint),
111	/// An arbitrary-precision decimal
112	Decimal(Decimal),
113	/// A container that can hold any value type
114	Any(Box<Value>),
115	/// A dictionary entry identifier
116	DictionaryId(DictionaryEntryId),
117	/// A type value (first-class type identifier)
118	Type(Type),
119	/// An ordered list of values
120	List(Vec<Value>),
121}
122
123fn default_none_inner() -> Type {
124	Type::Any
125}
126
127impl Value {
128	pub fn none() -> Self {
129		Value::None {
130			inner: Type::Any,
131		}
132	}
133
134	pub fn none_of(ty: Type) -> Self {
135		Value::None {
136			inner: ty,
137		}
138	}
139
140	pub fn bool(v: impl Into<bool>) -> Self {
141		Value::Boolean(v.into())
142	}
143
144	pub fn float4(v: impl Into<f32>) -> Self {
145		OrderedF32::try_from(v.into()).map(Value::Float4).unwrap_or(Value::None {
146			inner: Type::Float4,
147		})
148	}
149
150	pub fn float8(v: impl Into<f64>) -> Self {
151		OrderedF64::try_from(v.into()).map(Value::Float8).unwrap_or(Value::None {
152			inner: Type::Float8,
153		})
154	}
155
156	pub fn int1(v: impl Into<i8>) -> Self {
157		Value::Int1(v.into())
158	}
159
160	pub fn int2(v: impl Into<i16>) -> Self {
161		Value::Int2(v.into())
162	}
163
164	pub fn int4(v: impl Into<i32>) -> Self {
165		Value::Int4(v.into())
166	}
167
168	pub fn int8(v: impl Into<i64>) -> Self {
169		Value::Int8(v.into())
170	}
171
172	pub fn int16(v: impl Into<i128>) -> Self {
173		Value::Int16(v.into())
174	}
175
176	pub fn utf8(v: impl Into<String>) -> Self {
177		Value::Utf8(v.into())
178	}
179
180	pub fn uint1(v: impl Into<u8>) -> Self {
181		Value::Uint1(v.into())
182	}
183
184	pub fn uint2(v: impl Into<u16>) -> Self {
185		Value::Uint2(v.into())
186	}
187
188	pub fn uint4(v: impl Into<u32>) -> Self {
189		Value::Uint4(v.into())
190	}
191
192	pub fn uint8(v: impl Into<u64>) -> Self {
193		Value::Uint8(v.into())
194	}
195
196	pub fn uint16(v: impl Into<u128>) -> Self {
197		Value::Uint16(v.into())
198	}
199
200	pub fn date(v: impl Into<Date>) -> Self {
201		Value::Date(v.into())
202	}
203
204	pub fn datetime(v: impl Into<DateTime>) -> Self {
205		Value::DateTime(v.into())
206	}
207
208	pub fn time(v: impl Into<Time>) -> Self {
209		Value::Time(v.into())
210	}
211
212	pub fn duration(v: impl Into<Duration>) -> Self {
213		Value::Duration(v.into())
214	}
215
216	pub fn identity_id(v: impl Into<IdentityId>) -> Self {
217		Value::IdentityId(v.into())
218	}
219
220	pub fn uuid4(v: impl Into<Uuid4>) -> Self {
221		Value::Uuid4(v.into())
222	}
223
224	pub fn uuid7(v: impl Into<Uuid7>) -> Self {
225		Value::Uuid7(v.into())
226	}
227
228	pub fn blob(v: impl Into<Blob>) -> Self {
229		Value::Blob(v.into())
230	}
231
232	pub fn any(v: impl Into<Value>) -> Self {
233		Value::Any(Box::new(v.into()))
234	}
235
236	pub fn list(items: Vec<Value>) -> Self {
237		Value::List(items)
238	}
239}
240
241impl PartialEq for Value {
242	fn eq(&self, other: &Self) -> bool {
243		match (self, other) {
244			(
245				Value::None {
246					..
247				},
248				Value::None {
249					..
250				},
251			) => true,
252			(Value::Boolean(l), Value::Boolean(r)) => l == r,
253			(Value::Float4(l), Value::Float4(r)) => l == r,
254			(Value::Float8(l), Value::Float8(r)) => l == r,
255			(Value::Int1(l), Value::Int1(r)) => l == r,
256			(Value::Int2(l), Value::Int2(r)) => l == r,
257			(Value::Int4(l), Value::Int4(r)) => l == r,
258			(Value::Int8(l), Value::Int8(r)) => l == r,
259			(Value::Int16(l), Value::Int16(r)) => l == r,
260			(Value::Utf8(l), Value::Utf8(r)) => l == r,
261			(Value::Uint1(l), Value::Uint1(r)) => l == r,
262			(Value::Uint2(l), Value::Uint2(r)) => l == r,
263			(Value::Uint4(l), Value::Uint4(r)) => l == r,
264			(Value::Uint8(l), Value::Uint8(r)) => l == r,
265			(Value::Uint16(l), Value::Uint16(r)) => l == r,
266			(Value::Date(l), Value::Date(r)) => l == r,
267			(Value::DateTime(l), Value::DateTime(r)) => l == r,
268			(Value::Time(l), Value::Time(r)) => l == r,
269			(Value::Duration(l), Value::Duration(r)) => l == r,
270			(Value::IdentityId(l), Value::IdentityId(r)) => l == r,
271			(Value::Uuid4(l), Value::Uuid4(r)) => l == r,
272			(Value::Uuid7(l), Value::Uuid7(r)) => l == r,
273			(Value::Blob(l), Value::Blob(r)) => l == r,
274			(Value::Int(l), Value::Int(r)) => l == r,
275			(Value::Uint(l), Value::Uint(r)) => l == r,
276			(Value::Decimal(l), Value::Decimal(r)) => l == r,
277			(Value::Any(l), Value::Any(r)) => l == r,
278			(Value::DictionaryId(l), Value::DictionaryId(r)) => l == r,
279			(Value::Type(l), Value::Type(r)) => l == r,
280			(Value::List(l), Value::List(r)) => l == r,
281			_ => false,
282		}
283	}
284}
285
286impl Eq for Value {}
287
288impl hash::Hash for Value {
289	fn hash<H: hash::Hasher>(&self, state: &mut H) {
290		mem::discriminant(self).hash(state);
291		match self {
292			Value::None {
293				..
294			} => {} // All Nones hash identically
295			Value::Boolean(v) => v.hash(state),
296			Value::Float4(v) => v.hash(state),
297			Value::Float8(v) => v.hash(state),
298			Value::Int1(v) => v.hash(state),
299			Value::Int2(v) => v.hash(state),
300			Value::Int4(v) => v.hash(state),
301			Value::Int8(v) => v.hash(state),
302			Value::Int16(v) => v.hash(state),
303			Value::Utf8(v) => v.hash(state),
304			Value::Uint1(v) => v.hash(state),
305			Value::Uint2(v) => v.hash(state),
306			Value::Uint4(v) => v.hash(state),
307			Value::Uint8(v) => v.hash(state),
308			Value::Uint16(v) => v.hash(state),
309			Value::Date(v) => v.hash(state),
310			Value::DateTime(v) => v.hash(state),
311			Value::Time(v) => v.hash(state),
312			Value::Duration(v) => v.hash(state),
313			Value::IdentityId(v) => v.hash(state),
314			Value::Uuid4(v) => v.hash(state),
315			Value::Uuid7(v) => v.hash(state),
316			Value::Blob(v) => v.hash(state),
317			Value::Int(v) => v.hash(state),
318			Value::Uint(v) => v.hash(state),
319			Value::Decimal(v) => v.hash(state),
320			Value::Any(v) => v.hash(state),
321			Value::DictionaryId(v) => v.hash(state),
322			Value::Type(v) => v.hash(state),
323			Value::List(v) => v.hash(state),
324		}
325	}
326}
327
328impl PartialOrd for Value {
329	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
330		match (self, other) {
331			(Value::Boolean(l), Value::Boolean(r)) => l.partial_cmp(r),
332			(Value::Float4(l), Value::Float4(r)) => l.partial_cmp(r),
333			(Value::Float8(l), Value::Float8(r)) => l.partial_cmp(r),
334			(Value::Int1(l), Value::Int1(r)) => l.partial_cmp(r),
335			(Value::Int2(l), Value::Int2(r)) => l.partial_cmp(r),
336			(Value::Int4(l), Value::Int4(r)) => l.partial_cmp(r),
337			(Value::Int8(l), Value::Int8(r)) => l.partial_cmp(r),
338			(Value::Int16(l), Value::Int16(r)) => l.partial_cmp(r),
339			(Value::Utf8(l), Value::Utf8(r)) => l.partial_cmp(r),
340			(Value::Uint1(l), Value::Uint1(r)) => l.partial_cmp(r),
341			(Value::Uint2(l), Value::Uint2(r)) => l.partial_cmp(r),
342			(Value::Uint4(l), Value::Uint4(r)) => l.partial_cmp(r),
343			(Value::Uint8(l), Value::Uint8(r)) => l.partial_cmp(r),
344			(Value::Uint16(l), Value::Uint16(r)) => l.partial_cmp(r),
345			(Value::Date(l), Value::Date(r)) => l.partial_cmp(r),
346			(Value::DateTime(l), Value::DateTime(r)) => l.partial_cmp(r),
347			(Value::Time(l), Value::Time(r)) => l.partial_cmp(r),
348			(Value::Duration(l), Value::Duration(r)) => l.partial_cmp(r),
349			(Value::IdentityId(l), Value::IdentityId(r)) => l.partial_cmp(r),
350			(Value::Uuid4(l), Value::Uuid4(r)) => l.partial_cmp(r),
351			(Value::Uuid7(l), Value::Uuid7(r)) => l.partial_cmp(r),
352			(Value::Blob(l), Value::Blob(r)) => l.partial_cmp(r),
353			(Value::Int(l), Value::Int(r)) => l.partial_cmp(r),
354			(Value::Uint(l), Value::Uint(r)) => l.partial_cmp(r),
355			(Value::Decimal(l), Value::Decimal(r)) => l.partial_cmp(r),
356			(Value::DictionaryId(l), Value::DictionaryId(r)) => l.to_u128().partial_cmp(&r.to_u128()),
357			(Value::Type(l), Value::Type(r)) => l.partial_cmp(r),
358			(Value::List(_), Value::List(_)) => None, // Lists are not orderable
359			(Value::Any(_), Value::Any(_)) => None,   // Any values are not comparable
360			(
361				Value::None {
362					..
363				},
364				Value::None {
365					..
366				},
367			) => Some(Ordering::Equal),
368			// None sorts after all other values (similar to NULL in SQL)
369			(
370				Value::None {
371					..
372				},
373				_,
374			) => Some(Ordering::Greater),
375			(
376				_,
377				Value::None {
378					..
379				},
380			) => Some(Ordering::Less),
381			(left, right) => {
382				unimplemented!("partial cmp {left:?} {right:?}")
383			}
384		}
385	}
386}
387
388impl Ord for Value {
389	fn cmp(&self, other: &Self) -> Ordering {
390		match (self, other) {
391			(
392				Value::None {
393					..
394				},
395				Value::None {
396					..
397				},
398			) => Ordering::Equal,
399			(
400				Value::None {
401					..
402				},
403				_,
404			) => Ordering::Greater,
405			(
406				_,
407				Value::None {
408					..
409				},
410			) => Ordering::Less,
411			(Value::Boolean(l), Value::Boolean(r)) => l.cmp(r),
412			(Value::Float4(l), Value::Float4(r)) => l.cmp(r),
413			(Value::Float8(l), Value::Float8(r)) => l.cmp(r),
414			(Value::Int1(l), Value::Int1(r)) => l.cmp(r),
415			(Value::Int2(l), Value::Int2(r)) => l.cmp(r),
416			(Value::Int4(l), Value::Int4(r)) => l.cmp(r),
417			(Value::Int8(l), Value::Int8(r)) => l.cmp(r),
418			(Value::Int16(l), Value::Int16(r)) => l.cmp(r),
419			(Value::Utf8(l), Value::Utf8(r)) => l.cmp(r),
420			(Value::Uint1(l), Value::Uint1(r)) => l.cmp(r),
421			(Value::Uint2(l), Value::Uint2(r)) => l.cmp(r),
422			(Value::Uint4(l), Value::Uint4(r)) => l.cmp(r),
423			(Value::Uint8(l), Value::Uint8(r)) => l.cmp(r),
424			(Value::Uint16(l), Value::Uint16(r)) => l.cmp(r),
425			(Value::Date(l), Value::Date(r)) => l.cmp(r),
426			(Value::DateTime(l), Value::DateTime(r)) => l.cmp(r),
427			(Value::Time(l), Value::Time(r)) => l.cmp(r),
428			(Value::Duration(l), Value::Duration(r)) => l.cmp(r),
429			(Value::IdentityId(l), Value::IdentityId(r)) => l.cmp(r),
430			(Value::Uuid4(l), Value::Uuid4(r)) => l.cmp(r),
431			(Value::Uuid7(l), Value::Uuid7(r)) => l.cmp(r),
432			(Value::Blob(l), Value::Blob(r)) => l.cmp(r),
433			(Value::Int(l), Value::Int(r)) => l.cmp(r),
434			(Value::Uint(l), Value::Uint(r)) => l.cmp(r),
435			(Value::Decimal(l), Value::Decimal(r)) => l.cmp(r),
436			(Value::DictionaryId(l), Value::DictionaryId(r)) => l.to_u128().cmp(&r.to_u128()),
437			(Value::Type(l), Value::Type(r)) => l.cmp(r),
438			(Value::List(_), Value::List(_)) => unreachable!("List values are not orderable"),
439			(Value::Any(_), Value::Any(_)) => unreachable!("Any values are not orderable"),
440			_ => unimplemented!(),
441		}
442	}
443}
444
445impl Display for Value {
446	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
447		match self {
448			Value::Boolean(true) => f.write_str("true"),
449			Value::Boolean(false) => f.write_str("false"),
450			Value::Float4(value) => Display::fmt(value, f),
451			Value::Float8(value) => Display::fmt(value, f),
452			Value::Int1(value) => Display::fmt(value, f),
453			Value::Int2(value) => Display::fmt(value, f),
454			Value::Int4(value) => Display::fmt(value, f),
455			Value::Int8(value) => Display::fmt(value, f),
456			Value::Int16(value) => Display::fmt(value, f),
457			Value::Utf8(value) => Display::fmt(value, f),
458			Value::Uint1(value) => Display::fmt(value, f),
459			Value::Uint2(value) => Display::fmt(value, f),
460			Value::Uint4(value) => Display::fmt(value, f),
461			Value::Uint8(value) => Display::fmt(value, f),
462			Value::Uint16(value) => Display::fmt(value, f),
463			Value::Date(value) => Display::fmt(value, f),
464			Value::DateTime(value) => Display::fmt(value, f),
465			Value::Time(value) => Display::fmt(value, f),
466			Value::Duration(value) => Display::fmt(value, f),
467			Value::IdentityId(value) => Display::fmt(value, f),
468			Value::Uuid4(value) => Display::fmt(value, f),
469			Value::Uuid7(value) => Display::fmt(value, f),
470			Value::Blob(value) => Display::fmt(value, f),
471			Value::Int(value) => Display::fmt(value, f),
472			Value::Uint(value) => Display::fmt(value, f),
473			Value::Decimal(value) => Display::fmt(value, f),
474			Value::Any(value) => Display::fmt(value, f),
475			Value::DictionaryId(value) => Display::fmt(value, f),
476			Value::Type(value) => Display::fmt(value, f),
477			Value::List(items) => {
478				f.write_str("(")?;
479				for (i, item) in items.iter().enumerate() {
480					if i > 0 {
481						f.write_str(", ")?;
482					}
483					Display::fmt(item, f)?;
484				}
485				f.write_str(")")
486			}
487			Value::None {
488				..
489			} => f.write_str("none"),
490		}
491	}
492}
493
494impl Value {
495	pub fn get_type(&self) -> Type {
496		match self {
497			Value::None {
498				inner,
499			} => Type::Option(Box::new(inner.clone())),
500			Value::Boolean(_) => Type::Boolean,
501			Value::Float4(_) => Type::Float4,
502			Value::Float8(_) => Type::Float8,
503			Value::Int1(_) => Type::Int1,
504			Value::Int2(_) => Type::Int2,
505			Value::Int4(_) => Type::Int4,
506			Value::Int8(_) => Type::Int8,
507			Value::Int16(_) => Type::Int16,
508			Value::Utf8(_) => Type::Utf8,
509			Value::Uint1(_) => Type::Uint1,
510			Value::Uint2(_) => Type::Uint2,
511			Value::Uint4(_) => Type::Uint4,
512			Value::Uint8(_) => Type::Uint8,
513			Value::Uint16(_) => Type::Uint16,
514			Value::Date(_) => Type::Date,
515			Value::DateTime(_) => Type::DateTime,
516			Value::Time(_) => Type::Time,
517			Value::Duration(_) => Type::Duration,
518			Value::IdentityId(_) => Type::IdentityId,
519			Value::Uuid4(_) => Type::Uuid4,
520			Value::Uuid7(_) => Type::Uuid7,
521			Value::Blob(_) => Type::Blob,
522			Value::Int(_) => Type::Int,
523			Value::Uint(_) => Type::Uint,
524			Value::Decimal(_) => Type::Decimal,
525			Value::Any(_) => Type::Any,
526			Value::DictionaryId(_) => Type::DictionaryId,
527			Value::Type(t) => t.clone(),
528			Value::List(items) => {
529				let element_type = items.first().map(|v| v.get_type()).unwrap_or(Type::Any);
530				Type::list_of(element_type)
531			}
532		}
533	}
534}