1use reifydb_value::value::{Value, value_type::ValueType};
5
6use crate::error::{DecodeError, EncodeError};
7
8pub const MAX_OPTION_DEPTH: u8 = 3;
9pub const RESERVED_KIND: u8 = 63;
10pub const EXTENDED_TYPE_TAG: u8 = 0xFF;
11
12#[repr(u8)]
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum ValueKind {
15 None = 0,
16 Boolean = 1,
17 Float4 = 2,
18 Float8 = 3,
19 Int1 = 4,
20 Int2 = 5,
21 Int4 = 6,
22 Int8 = 7,
23 Int16 = 8,
24 Utf8 = 9,
25 Uint1 = 10,
26 Uint2 = 11,
27 Uint4 = 12,
28 Uint8 = 13,
29 Uint16 = 14,
30 Date = 15,
31 DateTime = 16,
32 Time = 17,
33 Duration = 18,
34 IdentityId = 19,
35 Uuid4 = 20,
36 Uuid7 = 21,
37 Blob = 22,
38 Decimal = 23,
39 Any = 24,
40 DictionaryId = 25,
41 Type = 26,
42 List = 27,
43 Record = 28,
44 Tuple = 29,
45 Digest = 30,
46}
47
48impl ValueKind {
49 pub const ALL: [ValueKind; 31] = [
50 ValueKind::None,
51 ValueKind::Boolean,
52 ValueKind::Float4,
53 ValueKind::Float8,
54 ValueKind::Int1,
55 ValueKind::Int2,
56 ValueKind::Int4,
57 ValueKind::Int8,
58 ValueKind::Int16,
59 ValueKind::Utf8,
60 ValueKind::Uint1,
61 ValueKind::Uint2,
62 ValueKind::Uint4,
63 ValueKind::Uint8,
64 ValueKind::Uint16,
65 ValueKind::Date,
66 ValueKind::DateTime,
67 ValueKind::Time,
68 ValueKind::Duration,
69 ValueKind::IdentityId,
70 ValueKind::Uuid4,
71 ValueKind::Uuid7,
72 ValueKind::Blob,
73 ValueKind::Decimal,
74 ValueKind::Any,
75 ValueKind::DictionaryId,
76 ValueKind::Type,
77 ValueKind::List,
78 ValueKind::Record,
79 ValueKind::Tuple,
80 ValueKind::Digest,
81 ];
82
83 pub const fn byte(self) -> u8 {
84 self as u8
85 }
86
87 pub fn from_byte(byte: u8) -> Option<ValueKind> {
88 if byte < Self::ALL.len() as u8 {
89 Some(Self::ALL[byte as usize])
90 } else {
91 None
92 }
93 }
94
95 pub fn of_value(value: &Value) -> ValueKind {
96 match value {
97 Value::None {
98 ..
99 } => ValueKind::None,
100 Value::Boolean(_) => ValueKind::Boolean,
101 Value::Float4(_) => ValueKind::Float4,
102 Value::Float8(_) => ValueKind::Float8,
103 Value::Int1(_) => ValueKind::Int1,
104 Value::Int2(_) => ValueKind::Int2,
105 Value::Int4(_) => ValueKind::Int4,
106 Value::Int8(_) => ValueKind::Int8,
107 Value::Int16(_) => ValueKind::Int16,
108 Value::Utf8(_) => ValueKind::Utf8,
109 Value::Uint1(_) => ValueKind::Uint1,
110 Value::Uint2(_) => ValueKind::Uint2,
111 Value::Uint4(_) => ValueKind::Uint4,
112 Value::Uint8(_) => ValueKind::Uint8,
113 Value::Uint16(_) => ValueKind::Uint16,
114 Value::Date(_) => ValueKind::Date,
115 Value::DateTime(_) => ValueKind::DateTime,
116 Value::Time(_) => ValueKind::Time,
117 Value::Duration(_) => ValueKind::Duration,
118 Value::IdentityId(_) => ValueKind::IdentityId,
119 Value::Uuid4(_) => ValueKind::Uuid4,
120 Value::Uuid7(_) => ValueKind::Uuid7,
121 Value::Blob(_) => ValueKind::Blob,
122 Value::Decimal(_) => ValueKind::Decimal,
123 Value::Any(_) => ValueKind::Any,
124 Value::DictionaryId(_) => ValueKind::DictionaryId,
125 Value::Type(_) => ValueKind::Type,
126 Value::List(_) => ValueKind::List,
127 Value::Record(_) => ValueKind::Record,
128 Value::Tuple(_) => ValueKind::Tuple,
129 Value::Digest(_) => ValueKind::Digest,
130 }
131 }
132
133 pub fn of_type(ty: &ValueType) -> ValueKind {
134 match ty {
135 ValueType::Option(inner) => Self::of_type(inner),
136 ValueType::Boolean => ValueKind::Boolean,
137 ValueType::Float4 => ValueKind::Float4,
138 ValueType::Float8 => ValueKind::Float8,
139 ValueType::Int1 => ValueKind::Int1,
140 ValueType::Int2 => ValueKind::Int2,
141 ValueType::Int4 => ValueKind::Int4,
142 ValueType::Int8 => ValueKind::Int8,
143 ValueType::Int16 => ValueKind::Int16,
144 ValueType::Utf8 => ValueKind::Utf8,
145 ValueType::Uint1 => ValueKind::Uint1,
146 ValueType::Uint2 => ValueKind::Uint2,
147 ValueType::Uint4 => ValueKind::Uint4,
148 ValueType::Uint8 => ValueKind::Uint8,
149 ValueType::Uint16 => ValueKind::Uint16,
150 ValueType::Date => ValueKind::Date,
151 ValueType::DateTime => ValueKind::DateTime,
152 ValueType::Time => ValueKind::Time,
153 ValueType::Duration => ValueKind::Duration,
154 ValueType::IdentityId => ValueKind::IdentityId,
155 ValueType::Uuid4 => ValueKind::Uuid4,
156 ValueType::Uuid7 => ValueKind::Uuid7,
157 ValueType::Blob => ValueKind::Blob,
158 ValueType::Decimal {
159 ..
160 } => ValueKind::Decimal,
161 ValueType::Any => ValueKind::Any,
162 ValueType::DictionaryId => ValueKind::DictionaryId,
163 ValueType::List(_) => ValueKind::List,
164 ValueType::Record(_) => ValueKind::Record,
165 ValueType::Tuple(_) => ValueKind::Tuple,
166 ValueType::Digest {
167 ..
168 } => ValueKind::Digest,
169 }
170 }
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
174pub struct TypeTag(u8);
175
176impl TypeTag {
177 pub fn new(kind: ValueKind, depth: u8) -> Result<TypeTag, EncodeError> {
178 if depth > MAX_OPTION_DEPTH {
179 return Err(EncodeError::OptionDepthTooDeep {
180 depth: depth as u32,
181 max: MAX_OPTION_DEPTH,
182 });
183 }
184 Ok(TypeTag((depth << 6) | kind.byte()))
185 }
186
187 pub const fn byte(self) -> u8 {
188 self.0
189 }
190
191 pub const fn depth(self) -> u8 {
192 self.0 >> 6
193 }
194
195 pub const fn kind_bits(self) -> u8 {
196 self.0 & 0x3F
197 }
198
199 pub fn kind(self) -> Option<ValueKind> {
200 ValueKind::from_byte(self.kind_bits())
201 }
202
203 pub fn from_byte(byte: u8) -> Result<TypeTag, DecodeError> {
204 let kind_bits = byte & 0x3F;
205 if kind_bits == RESERVED_KIND {
206 return Err(DecodeError::ReservedTag(byte));
207 }
208 if ValueKind::from_byte(kind_bits).is_none() {
209 return Err(DecodeError::UnknownTypeCode(byte));
210 }
211 let tag = TypeTag(byte);
212 if tag.depth() > 0 && kind_bits == ValueKind::None.byte() {
213 return Err(DecodeError::InvalidData(format!(
214 "tag byte 0x{byte:02X} wraps the none kind in option depth {}",
215 tag.depth()
216 )));
217 }
218 Ok(tag)
219 }
220
221 pub fn of_type(ty: &ValueType) -> Result<TypeTag, EncodeError> {
222 let (base, depth) = peel_options(ty);
223 if depth > MAX_OPTION_DEPTH as u32 {
224 return Err(EncodeError::OptionDepthTooDeep {
225 depth,
226 max: MAX_OPTION_DEPTH,
227 });
228 }
229 Self::new(ValueKind::of_type(base), depth as u8)
230 }
231
232 pub fn to_type(self) -> Result<ValueType, DecodeError> {
233 let base = match self.kind().ok_or(DecodeError::UnknownTypeCode(self.0))? {
234 ValueKind::None | ValueKind::Type => {
235 return Err(DecodeError::UnsupportedType(format!(
236 "kind {:?} has no standalone value type",
237 self.kind()
238 )));
239 }
240 ValueKind::Digest => {
241 return Err(DecodeError::UnsupportedType(
242 "kind Digest needs its inner type and accuracy, which a type tag does not carry"
243 .to_string(),
244 ));
245 }
246 ValueKind::Boolean => ValueType::Boolean,
247 ValueKind::Float4 => ValueType::Float4,
248 ValueKind::Float8 => ValueType::Float8,
249 ValueKind::Int1 => ValueType::Int1,
250 ValueKind::Int2 => ValueType::Int2,
251 ValueKind::Int4 => ValueType::Int4,
252 ValueKind::Int8 => ValueType::Int8,
253 ValueKind::Int16 => ValueType::Int16,
254 ValueKind::Utf8 => ValueType::Utf8,
255 ValueKind::Uint1 => ValueType::Uint1,
256 ValueKind::Uint2 => ValueType::Uint2,
257 ValueKind::Uint4 => ValueType::Uint4,
258 ValueKind::Uint8 => ValueType::Uint8,
259 ValueKind::Uint16 => ValueType::Uint16,
260 ValueKind::Date => ValueType::Date,
261 ValueKind::DateTime => ValueType::DateTime,
262 ValueKind::Time => ValueType::Time,
263 ValueKind::Duration => ValueType::Duration,
264 ValueKind::IdentityId => ValueType::IdentityId,
265 ValueKind::Uuid4 => ValueType::Uuid4,
266 ValueKind::Uuid7 => ValueType::Uuid7,
267 ValueKind::Blob => ValueType::Blob,
268 ValueKind::Decimal => ValueType::DECIMAL,
269 ValueKind::Any => ValueType::Any,
270 ValueKind::DictionaryId => ValueType::DictionaryId,
271 ValueKind::List => ValueType::List(Box::new(ValueType::Any)),
272 ValueKind::Record => ValueType::Record(Vec::new()),
273 ValueKind::Tuple => ValueType::Tuple(Vec::new()),
274 };
275 Ok((0..self.depth()).fold(base, |ty, _| ValueType::Option(Box::new(ty))))
276 }
277}
278
279pub(crate) fn peel_options(ty: &ValueType) -> (&ValueType, u32) {
280 let mut depth = 0u32;
281 let mut base = ty;
282 while let ValueType::Option(inner) = base {
283 depth += 1;
284 base = inner;
285 }
286 (base, depth)
287}
288
289pub fn type_tag_byte(ty: &ValueType) -> u8 {
290 TypeTag::of_type(ty).expect("option nesting exceeds the type tag capacity").byte()
291}
292
293pub fn value_type_from_tag_byte(byte: u8) -> ValueType {
294 TypeTag::from_byte(byte).and_then(TypeTag::to_type).expect("invalid persisted type tag byte")
295}