Skip to main content

reifydb_value/value/
dictionary.rs

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