Skip to main content

reifydb_type/value/
dictionary.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2025 ReifyDB
3
4use std::{
5	fmt,
6	fmt::{Display, Formatter},
7	ops::Deref,
8};
9
10use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
11
12use super::r#type::Type;
13use crate::{error, error::diagnostic::dictionary::dictionary_entry_id_capacity_exceeded};
14
15/// A dictionary entry ID that can be one of several unsigned integer sizes.
16/// The variant used depends on the dictionary's `id_type` configuration.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub enum DictionaryEntryId {
19	U1(u8),
20	U2(u16),
21	U4(u32),
22	U8(u64),
23	U16(u128),
24}
25
26impl DictionaryEntryId {
27	/// Create a DictionaryEntryId from a u128 value and the target Type.
28	/// Returns an error if the value doesn't fit in the specified type.
29	pub fn from_u128(value: u128, id_type: Type) -> crate::Result<Self> {
30		match id_type {
31			Type::Uint1 => {
32				if value > u8::MAX as u128 {
33					return Err(error!(dictionary_entry_id_capacity_exceeded(
34						Type::Uint1,
35						value,
36						u8::MAX as u128
37					)));
38				}
39				Ok(Self::U1(value as u8))
40			}
41			Type::Uint2 => {
42				if value > u16::MAX as u128 {
43					return Err(error!(dictionary_entry_id_capacity_exceeded(
44						Type::Uint2,
45						value,
46						u16::MAX as u128
47					)));
48				}
49				Ok(Self::U2(value as u16))
50			}
51			Type::Uint4 => {
52				if value > u32::MAX as u128 {
53					return Err(error!(dictionary_entry_id_capacity_exceeded(
54						Type::Uint4,
55						value,
56						u32::MAX as u128
57					)));
58				}
59				Ok(Self::U4(value as u32))
60			}
61			Type::Uint8 => {
62				if value > u64::MAX as u128 {
63					return Err(error!(dictionary_entry_id_capacity_exceeded(
64						Type::Uint8,
65						value,
66						u64::MAX as u128
67					)));
68				}
69				Ok(Self::U8(value as u64))
70			}
71			Type::Uint16 => Ok(Self::U16(value)),
72			// FIXME replace me with error
73			_ => unimplemented!(
74				"Invalid dictionary id_type: {:?}. Must be Uint1, Uint2, Uint4, Uint8, or Uint16",
75				id_type
76			),
77		}
78	}
79
80	/// Convert this ID to a u128 value for internal storage/computation.
81	pub fn to_u128(&self) -> u128 {
82		match self {
83			Self::U1(v) => *v as u128,
84			Self::U2(v) => *v as u128,
85			Self::U4(v) => *v as u128,
86			Self::U8(v) => *v as u128,
87			Self::U16(v) => *v,
88		}
89	}
90
91	/// Get the Type this ID represents.
92	pub fn id_type(&self) -> Type {
93		match self {
94			Self::U1(_) => Type::Uint1,
95			Self::U2(_) => Type::Uint2,
96			Self::U4(_) => Type::Uint4,
97			Self::U8(_) => Type::Uint8,
98			Self::U16(_) => Type::Uint16,
99		}
100	}
101
102	/// Convert this DictionaryEntryId to a Value.
103	pub fn to_value(self) -> super::Value {
104		super::Value::DictionaryId(self)
105	}
106
107	/// Create a DictionaryEntryId from a Value.
108	/// Returns None if the Value is not a DictionaryId or unsigned integer type.
109	pub fn from_value(value: &super::Value) -> Option<Self> {
110		match value {
111			super::Value::DictionaryId(id) => Some(*id),
112			super::Value::Uint1(v) => Some(Self::U1(*v)),
113			super::Value::Uint2(v) => Some(Self::U2(*v)),
114			super::Value::Uint4(v) => Some(Self::U4(*v)),
115			super::Value::Uint8(v) => Some(Self::U8(*v)),
116			super::Value::Uint16(v) => Some(Self::U16(*v)),
117			_ => None,
118		}
119	}
120}
121
122impl PartialOrd for DictionaryEntryId {
123	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
124		Some(self.cmp(other))
125	}
126}
127
128impl Ord for DictionaryEntryId {
129	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
130		self.to_u128().cmp(&other.to_u128())
131	}
132}
133
134impl Default for DictionaryEntryId {
135	fn default() -> Self {
136		Self::U1(0)
137	}
138}
139
140impl std::fmt::Display for DictionaryEntryId {
141	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142		match self {
143			Self::U1(v) => write!(f, "{}", v),
144			Self::U2(v) => write!(f, "{}", v),
145			Self::U4(v) => write!(f, "{}", v),
146			Self::U8(v) => write!(f, "{}", v),
147			Self::U16(v) => write!(f, "{}", v),
148		}
149	}
150}
151
152#[repr(transparent)]
153#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
154pub struct DictionaryId(pub u64);
155
156impl Display for DictionaryId {
157	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158		Display::fmt(&self.0, f)
159	}
160}
161
162impl Deref for DictionaryId {
163	type Target = u64;
164
165	fn deref(&self) -> &Self::Target {
166		&self.0
167	}
168}
169
170impl PartialEq<u64> for DictionaryId {
171	fn eq(&self, other: &u64) -> bool {
172		self.0.eq(other)
173	}
174}
175
176impl From<DictionaryId> for u64 {
177	fn from(value: DictionaryId) -> Self {
178		value.0
179	}
180}
181
182impl DictionaryId {
183	/// Get the inner u64 value.
184	#[inline]
185	pub fn to_u64(self) -> u64 {
186		self.0
187	}
188}
189
190impl From<i32> for DictionaryId {
191	fn from(value: i32) -> Self {
192		Self(value as u64)
193	}
194}
195
196impl From<u64> for DictionaryId {
197	fn from(value: u64) -> Self {
198		Self(value)
199	}
200}
201
202impl Serialize for DictionaryId {
203	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
204	where
205		S: Serializer,
206	{
207		serializer.serialize_u64(self.0)
208	}
209}
210
211impl<'de> Deserialize<'de> for DictionaryId {
212	fn deserialize<D>(deserializer: D) -> Result<DictionaryId, D::Error>
213	where
214		D: Deserializer<'de>,
215	{
216		struct U64Visitor;
217
218		impl Visitor<'_> for U64Visitor {
219			type Value = DictionaryId;
220
221			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
222				formatter.write_str("an unsigned 64-bit number")
223			}
224
225			fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
226				Ok(DictionaryId(value))
227			}
228		}
229
230		deserializer.deserialize_u64(U64Visitor)
231	}
232}
233
234#[cfg(test)]
235pub mod tests {
236	use super::*;
237
238	#[test]
239	fn test_from_u128_u1() {
240		let id = DictionaryEntryId::from_u128(42, Type::Uint1).unwrap();
241		assert_eq!(id, DictionaryEntryId::U1(42));
242		assert_eq!(id.to_u128(), 42);
243		assert_eq!(id.id_type(), Type::Uint1);
244	}
245
246	#[test]
247	fn test_from_u128_u1_overflow() {
248		let err = DictionaryEntryId::from_u128(256, Type::Uint1).unwrap_err();
249		assert!(err.to_string().contains("DICT_001"));
250	}
251
252	#[test]
253	fn test_from_u128_u2() {
254		let id = DictionaryEntryId::from_u128(1000, Type::Uint2).unwrap();
255		assert_eq!(id, DictionaryEntryId::U2(1000));
256		assert_eq!(id.to_u128(), 1000);
257	}
258
259	#[test]
260	fn test_from_u128_u4() {
261		let id = DictionaryEntryId::from_u128(100_000, Type::Uint4).unwrap();
262		assert_eq!(id, DictionaryEntryId::U4(100_000));
263		assert_eq!(id.to_u128(), 100_000);
264	}
265
266	#[test]
267	fn test_from_u128_u8() {
268		let id = DictionaryEntryId::from_u128(10_000_000_000, Type::Uint8).unwrap();
269		assert_eq!(id, DictionaryEntryId::U8(10_000_000_000));
270		assert_eq!(id.to_u128(), 10_000_000_000);
271	}
272
273	#[test]
274	fn test_from_u128_u16() {
275		let large_value: u128 = u64::MAX as u128 + 1;
276		let id = DictionaryEntryId::from_u128(large_value, Type::Uint16).unwrap();
277		assert_eq!(id, DictionaryEntryId::U16(large_value));
278		assert_eq!(id.to_u128(), large_value);
279	}
280
281	#[test]
282	fn test_display() {
283		assert_eq!(format!("{}", DictionaryEntryId::U1(42)), "42");
284		assert_eq!(format!("{}", DictionaryEntryId::U8(12345)), "12345");
285	}
286}