1use crate::{Error, Result};
4use bytes::{Buf, BufMut};
5use serde::{Deserialize, Serialize};
6use std::cmp::Ordering;
7
8#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
10pub enum Value {
11 #[default]
13 Null,
14 Boolean(bool),
16 Integer(i64),
18 Real(f64),
20 Text(String),
22 Blob(Vec<u8>),
24 Timestamp(i64),
26}
27
28impl Value {
29 pub fn is_null(&self) -> bool {
31 matches!(self, Value::Null)
32 }
33
34 pub fn as_bool(&self) -> Option<bool> {
36 match self {
37 Value::Boolean(b) => Some(*b),
38 Value::Integer(i) => Some(*i != 0),
39 _ => None,
40 }
41 }
42
43 pub fn as_i64(&self) -> Option<i64> {
45 match self {
46 Value::Integer(i) => Some(*i),
47 Value::Real(r) => Some(*r as i64),
48 Value::Boolean(b) => Some(if *b { 1 } else { 0 }),
49 _ => None,
50 }
51 }
52
53 pub fn as_f64(&self) -> Option<f64> {
55 match self {
56 Value::Real(r) => Some(*r),
57 Value::Integer(i) => Some(*i as f64),
58 _ => None,
59 }
60 }
61
62 pub fn as_str(&self) -> Option<&str> {
64 match self {
65 Value::Text(s) => Some(s),
66 _ => None,
67 }
68 }
69
70 pub fn as_bytes(&self) -> Option<&[u8]> {
72 match self {
73 Value::Blob(b) => Some(b),
74 Value::Text(s) => Some(s.as_bytes()),
75 _ => None,
76 }
77 }
78
79 pub fn column_type(&self) -> ColumnType {
81 match self {
82 Value::Null => ColumnType::Integer, Value::Boolean(_) => ColumnType::Boolean,
84 Value::Integer(_) => ColumnType::Integer,
85 Value::Real(_) => ColumnType::Real,
86 Value::Text(_) => ColumnType::Text { max_len: None },
87 Value::Blob(_) => ColumnType::Blob { max_len: None },
88 Value::Timestamp(_) => ColumnType::Timestamp,
89 }
90 }
91
92 pub fn serialize(&self, buf: &mut impl BufMut) {
94 match self {
95 Value::Null => {
96 buf.put_u8(0);
97 }
98 Value::Boolean(b) => {
99 buf.put_u8(1);
100 buf.put_u8(if *b { 1 } else { 0 });
101 }
102 Value::Integer(i) => {
103 buf.put_u8(2);
104 buf.put_i64_le(*i);
105 }
106 Value::Real(r) => {
107 buf.put_u8(3);
108 buf.put_f64_le(*r);
109 }
110 Value::Text(s) => {
111 buf.put_u8(4);
112 buf.put_u32_le(s.len() as u32);
113 buf.put_slice(s.as_bytes());
114 }
115 Value::Blob(b) => {
116 buf.put_u8(5);
117 buf.put_u32_le(b.len() as u32);
118 buf.put_slice(b);
119 }
120 Value::Timestamp(ts) => {
121 buf.put_u8(6);
122 buf.put_i64_le(*ts);
123 }
124 }
125 }
126
127 pub fn deserialize(buf: &mut impl Buf) -> Result<Self> {
129 if buf.remaining() < 1 {
130 return Err(Error::Serialization("unexpected end of data".into()));
131 }
132
133 let tag = buf.get_u8();
134 match tag {
135 0 => Ok(Value::Null),
136 1 => {
137 if buf.remaining() < 1 {
138 return Err(Error::Serialization("unexpected end of data".into()));
139 }
140 Ok(Value::Boolean(buf.get_u8() != 0))
141 }
142 2 => {
143 if buf.remaining() < 8 {
144 return Err(Error::Serialization("unexpected end of data".into()));
145 }
146 Ok(Value::Integer(buf.get_i64_le()))
147 }
148 3 => {
149 if buf.remaining() < 8 {
150 return Err(Error::Serialization("unexpected end of data".into()));
151 }
152 Ok(Value::Real(buf.get_f64_le()))
153 }
154 4 => {
155 if buf.remaining() < 4 {
156 return Err(Error::Serialization("unexpected end of data".into()));
157 }
158 let len = buf.get_u32_le() as usize;
159 if buf.remaining() < len {
160 return Err(Error::Serialization("unexpected end of data".into()));
161 }
162 let data = if buf.chunk().len() >= len {
163 let slice = buf.chunk()[..len].to_vec();
164 buf.advance(len);
165 slice
166 } else {
167 let mut d = vec![0u8; len];
168 buf.copy_to_slice(&mut d);
169 d
170 };
171 String::from_utf8(data)
172 .map(Value::Text)
173 .map_err(|e| Error::Serialization(e.to_string()))
174 }
175 5 => {
176 if buf.remaining() < 4 {
177 return Err(Error::Serialization("unexpected end of data".into()));
178 }
179 let len = buf.get_u32_le() as usize;
180 if buf.remaining() < len {
181 return Err(Error::Serialization("unexpected end of data".into()));
182 }
183 let data = if buf.chunk().len() >= len {
184 let slice = buf.chunk()[..len].to_vec();
185 buf.advance(len);
186 slice
187 } else {
188 let mut d = vec![0u8; len];
189 buf.copy_to_slice(&mut d);
190 d
191 };
192 Ok(Value::Blob(data))
193 }
194 6 => {
195 if buf.remaining() < 8 {
196 return Err(Error::Serialization("unexpected end of data".into()));
197 }
198 Ok(Value::Timestamp(buf.get_i64_le()))
199 }
200 _ => Err(Error::Serialization(format!("unknown value tag: {}", tag))),
201 }
202 }
203
204 pub fn skip(buf: &mut impl Buf) -> Result<()> {
207 if buf.remaining() < 1 {
208 return Err(Error::Serialization("unexpected end of data".into()));
209 }
210 let tag = buf.get_u8();
211 let advance = match tag {
212 0 => 0, 1 => 1, 2 | 3 | 6 => 8, 4 | 5 => {
216 if buf.remaining() < 4 {
218 return Err(Error::Serialization("unexpected end of data".into()));
219 }
220 buf.get_u32_le() as usize
221 }
222 _ => return Err(Error::Serialization(format!("unknown value tag: {}", tag))),
223 };
224 if buf.remaining() < advance {
225 return Err(Error::Serialization("unexpected end of data".into()));
226 }
227 buf.advance(advance);
228 Ok(())
229 }
230
231 pub fn serialized_size(&self) -> usize {
233 match self {
234 Value::Null => 1,
235 Value::Boolean(_) => 2,
236 Value::Integer(_) => 9,
237 Value::Real(_) => 9,
238 Value::Text(s) => 5 + s.len(),
239 Value::Blob(b) => 5 + b.len(),
240 Value::Timestamp(_) => 9,
241 }
242 }
243
244 pub fn size_estimate(&self) -> usize {
246 match self {
247 Value::Null => 1,
248 Value::Boolean(_) => 1,
249 Value::Integer(_) => 8,
250 Value::Real(_) => 8,
251 Value::Text(s) => 24 + s.len(), Value::Blob(b) => 24 + b.len(), Value::Timestamp(_) => 8,
254 }
255 }
256}
257
258impl Eq for Value {}
259
260fn type_order(value: &Value) -> u8 {
262 match value {
263 Value::Null => 0,
264 Value::Boolean(_) => 1,
265 Value::Integer(_) => 2,
266 Value::Real(_) => 3,
267 Value::Text(_) => 4,
268 Value::Blob(_) => 5,
269 Value::Timestamp(_) => 6,
270 }
271}
272
273impl PartialOrd for Value {
274 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
275 Some(self.cmp(other))
276 }
277}
278
279impl Ord for Value {
280 fn cmp(&self, other: &Self) -> Ordering {
281 match (self, other) {
282 (Value::Null, Value::Null) => Ordering::Equal,
284 (Value::Null, _) => Ordering::Less,
285 (_, Value::Null) => Ordering::Greater,
286
287 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
289 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
290 (Value::Real(a), Value::Real(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
291 (Value::Text(a), Value::Text(b)) => a.cmp(b),
292 (Value::Blob(a), Value::Blob(b)) => a.cmp(b),
293 (Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
294
295 (Value::Integer(a), Value::Real(b)) => {
297 (*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
298 }
299 (Value::Real(a), Value::Integer(b)) => {
300 a.partial_cmp(&(*b as f64)).unwrap_or(Ordering::Equal)
301 }
302
303 (a, b) => type_order(a).cmp(&type_order(b)),
305 }
306 }
307}
308
309impl std::hash::Hash for Value {
310 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
311 std::mem::discriminant(self).hash(state);
312 match self {
313 Value::Null => {}
314 Value::Boolean(b) => b.hash(state),
315 Value::Integer(i) => i.hash(state),
316 Value::Real(r) => r.to_bits().hash(state),
317 Value::Text(s) => s.hash(state),
318 Value::Blob(b) => b.hash(state),
319 Value::Timestamp(ts) => ts.hash(state),
320 }
321 }
322}
323
324impl From<bool> for Value {
326 fn from(v: bool) -> Self {
327 Value::Boolean(v)
328 }
329}
330
331impl From<i32> for Value {
332 fn from(v: i32) -> Self {
333 Value::Integer(v as i64)
334 }
335}
336
337impl From<i64> for Value {
338 fn from(v: i64) -> Self {
339 Value::Integer(v)
340 }
341}
342
343impl From<f64> for Value {
344 fn from(v: f64) -> Self {
345 Value::Real(v)
346 }
347}
348
349impl From<String> for Value {
350 fn from(v: String) -> Self {
351 Value::Text(v)
352 }
353}
354
355impl From<&str> for Value {
356 fn from(v: &str) -> Self {
357 Value::Text(v.to_string())
358 }
359}
360
361impl From<Vec<u8>> for Value {
362 fn from(v: Vec<u8>) -> Self {
363 Value::Blob(v)
364 }
365}
366
367impl<T> From<Option<T>> for Value
368where
369 T: Into<Value>,
370{
371 fn from(v: Option<T>) -> Self {
372 match v {
373 Some(v) => v.into(),
374 None => Value::Null,
375 }
376 }
377}
378
379impl std::fmt::Display for Value {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381 match self {
382 Value::Null => write!(f, "NULL"),
383 Value::Boolean(b) => write!(f, "{}", b),
384 Value::Integer(i) => write!(f, "{}", i),
385 Value::Real(r) => write!(f, "{}", r),
386 Value::Text(s) => write!(f, "'{}'", s),
387 Value::Blob(b) => write!(f, "x'{}'", hex::encode(b)),
388 Value::Timestamp(ts) => write!(f, "{}", ts),
389 }
390 }
391}
392
393mod hex {
395 pub fn encode(data: &[u8]) -> String {
396 data.iter().map(|b| format!("{:02x}", b)).collect()
397 }
398}
399
400#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
402pub enum ColumnType {
403 Boolean,
404 Integer,
405 Real,
406 Text { max_len: Option<usize> },
407 Blob { max_len: Option<usize> },
408 Timestamp,
409}
410
411impl ColumnType {
412 pub fn is_compatible(&self, value: &Value) -> bool {
414 if value.is_null() {
415 return true; }
417
418 match (self, value) {
419 (ColumnType::Boolean, Value::Boolean(_)) => true,
420 (ColumnType::Integer, Value::Integer(_)) => true,
421 (ColumnType::Real, Value::Real(_)) => true,
422 (ColumnType::Real, Value::Integer(_)) => true, (ColumnType::Text { max_len }, Value::Text(s)) => {
424 max_len.is_none_or(|max| s.len() <= max)
425 }
426 (ColumnType::Blob { max_len }, Value::Blob(b)) => {
427 max_len.is_none_or(|max| b.len() <= max)
428 }
429 (ColumnType::Timestamp, Value::Timestamp(_)) => true,
430 (ColumnType::Timestamp, Value::Integer(_)) => true, _ => false,
432 }
433 }
434
435 pub fn coerce(&self, value: Value) -> Result<Value> {
437 if value.is_null() {
438 return Ok(Value::Null);
439 }
440
441 match (self, &value) {
442 (ColumnType::Boolean, Value::Boolean(_)) => Ok(value),
443 (ColumnType::Boolean, Value::Integer(i)) => Ok(Value::Boolean(*i != 0)),
444
445 (ColumnType::Integer, Value::Integer(_)) => Ok(value),
446 (ColumnType::Integer, Value::Real(r)) => Ok(Value::Integer(*r as i64)),
447 (ColumnType::Integer, Value::Boolean(b)) => Ok(Value::Integer(if *b { 1 } else { 0 })),
448
449 (ColumnType::Real, Value::Real(_)) => Ok(value),
450 (ColumnType::Real, Value::Integer(i)) => Ok(Value::Real(*i as f64)),
451
452 (ColumnType::Text { max_len }, Value::Text(s)) => {
453 if let Some(max) = max_len {
454 if s.len() > *max {
455 return Err(Error::TypeError {
456 expected: format!("TEXT({})", max),
457 actual: format!("TEXT({})", s.len()),
458 });
459 }
460 }
461 Ok(value)
462 }
463 (ColumnType::Text { .. }, Value::Integer(i)) => Ok(Value::Text(i.to_string())),
464 (ColumnType::Text { .. }, Value::Real(r)) => Ok(Value::Text(r.to_string())),
465
466 (ColumnType::Blob { max_len }, Value::Blob(b)) => {
467 if let Some(max) = max_len {
468 if b.len() > *max {
469 return Err(Error::TypeError {
470 expected: format!("BLOB({})", max),
471 actual: format!("BLOB({})", b.len()),
472 });
473 }
474 }
475 Ok(value)
476 }
477
478 (ColumnType::Timestamp, Value::Timestamp(_)) => Ok(value),
479 (ColumnType::Timestamp, Value::Integer(i)) => Ok(Value::Timestamp(*i)),
480
481 _ => Err(Error::TypeError {
482 expected: format!("{:?}", self),
483 actual: format!("{:?}", value.column_type()),
484 }),
485 }
486 }
487}
488
489impl std::fmt::Display for ColumnType {
490 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491 match self {
492 ColumnType::Boolean => write!(f, "BOOLEAN"),
493 ColumnType::Integer => write!(f, "INTEGER"),
494 ColumnType::Real => write!(f, "REAL"),
495 ColumnType::Text { max_len: Some(n) } => write!(f, "TEXT({})", n),
496 ColumnType::Text { max_len: None } => write!(f, "TEXT"),
497 ColumnType::Blob { max_len: Some(n) } => write!(f, "BLOB({})", n),
498 ColumnType::Blob { max_len: None } => write!(f, "BLOB"),
499 ColumnType::Timestamp => write!(f, "TIMESTAMP"),
500 }
501 }
502}
503
504#[cfg(test)]
505mod tests {
506 use super::*;
507
508 #[test]
509 fn test_value_serialization() {
510 let values = vec![
511 Value::Null,
512 Value::Boolean(true),
513 Value::Boolean(false),
514 Value::Integer(42),
515 Value::Integer(-100),
516 Value::Real(3.14159),
517 Value::Text("hello world".into()),
518 Value::Blob(vec![1, 2, 3, 4, 5]),
519 Value::Timestamp(1234567890),
520 ];
521
522 for original in values {
523 let mut buf = Vec::new();
524 original.serialize(&mut buf);
525
526 let mut cursor = &buf[..];
527 let deserialized = Value::deserialize(&mut cursor).unwrap();
528
529 assert_eq!(original, deserialized);
530 }
531 }
532
533 #[test]
534 fn test_value_ordering() {
535 assert!(Value::Null < Value::Integer(0));
536 assert!(Value::Integer(1) < Value::Integer(2));
537 assert!(Value::Text("a".into()) < Value::Text("b".into()));
538 }
539
540 #[test]
541 fn test_type_coercion() {
542 let int_type = ColumnType::Integer;
543 assert_eq!(
544 int_type.coerce(Value::Real(3.7)).unwrap(),
545 Value::Integer(3)
546 );
547
548 let text_type = ColumnType::Text { max_len: Some(5) };
549 assert!(text_type.coerce(Value::Text("hello".into())).is_ok());
550 assert!(text_type.coerce(Value::Text("hello!".into())).is_err());
551 }
552}