1use std::sync::atomic::{AtomicU64, Ordering};
60
61#[repr(u8)]
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub enum ValueTag {
65 Null = 0,
67 Bool = 1,
69 SmallInt = 2,
71 InlineString = 3,
73 HeapString = 4,
75 InlineBytes = 5,
77 HeapBytes = 6,
79 Float = 7,
81}
82
83impl ValueTag {
84 fn from_u8(v: u8) -> Option<Self> {
85 match v {
86 0 => Some(Self::Null),
87 1 => Some(Self::Bool),
88 2 => Some(Self::SmallInt),
89 3 => Some(Self::InlineString),
90 4 => Some(Self::HeapString),
91 5 => Some(Self::InlineBytes),
92 6 => Some(Self::HeapBytes),
93 7 => Some(Self::Float),
94 _ => None,
95 }
96 }
97}
98
99const MAX_INLINE_SIZE: usize = 7;
101
102const TAG_SHIFT: u32 = 61;
104
105const INLINE_LEN_SHIFT: u32 = 56;
107const INLINE_LEN_MASK: u64 = 0x0F; const INLINE_DATA_MASK: u64 = 0x00FF_FFFF_FFFF_FFFF; #[derive(Clone)]
122pub struct PolymorphicValue {
123 bits: u64,
125 heap: Option<Box<[u8]>>,
127}
128
129impl PolymorphicValue {
130 #[inline]
132 pub fn null() -> Self {
133 Self {
134 bits: (ValueTag::Null as u64) << TAG_SHIFT,
135 heap: None,
136 }
137 }
138
139 #[inline]
141 pub fn bool(v: bool) -> Self {
142 let bits = ((ValueTag::Bool as u64) << TAG_SHIFT) | (v as u64);
143 Self { bits, heap: None }
144 }
145
146 #[inline]
150 pub fn int(v: i64) -> Self {
151 if v >= -(1i64 << 55) && v < (1i64 << 55) {
153 let bits = ((ValueTag::SmallInt as u64) << TAG_SHIFT) | ((v as u64) & INLINE_DATA_MASK);
154 Self { bits, heap: None }
155 } else {
156 let bytes = v.to_le_bytes();
158 Self::heap_bytes(&bytes, ValueTag::HeapBytes)
159 }
160 }
161
162 pub fn string(s: &str) -> Self {
166 let bytes = s.as_bytes();
167 if bytes.len() <= MAX_INLINE_SIZE {
168 Self::inline_bytes(bytes, ValueTag::InlineString)
169 } else {
170 Self::heap_bytes(bytes, ValueTag::HeapString)
171 }
172 }
173
174 pub fn bytes(b: &[u8]) -> Self {
178 if b.len() <= MAX_INLINE_SIZE {
179 Self::inline_bytes(b, ValueTag::InlineBytes)
180 } else {
181 Self::heap_bytes(b, ValueTag::HeapBytes)
182 }
183 }
184
185 #[inline]
187 pub fn float(v: f64) -> Self {
188 let bits = v.to_bits();
190 let packed = ((ValueTag::Float as u64) << TAG_SHIFT) | (bits & INLINE_DATA_MASK);
191 Self {
192 bits: packed,
193 heap: Some(Box::new(bits.to_le_bytes())),
194 }
195 }
196
197 fn inline_bytes(data: &[u8], tag: ValueTag) -> Self {
199 debug_assert!(data.len() <= MAX_INLINE_SIZE);
200
201 let mut packed = 0u64;
202 for (i, &byte) in data.iter().enumerate() {
203 packed |= (byte as u64) << (i * 8);
204 }
205
206 let bits = ((tag as u64) << TAG_SHIFT) | ((data.len() as u64) << INLINE_LEN_SHIFT) | packed;
207
208 Self { bits, heap: None }
209 }
210
211 fn heap_bytes(data: &[u8], tag: ValueTag) -> Self {
213 let heap = data.to_vec().into_boxed_slice();
214 let bits = ((tag as u64) << TAG_SHIFT) | (data.len() as u64 & 0x1FFF_FFFF);
215 Self {
216 bits,
217 heap: Some(heap),
218 }
219 }
220
221 #[inline]
223 pub fn tag(&self) -> ValueTag {
224 ValueTag::from_u8((self.bits >> TAG_SHIFT) as u8 & 0x07).unwrap_or(ValueTag::Null)
225 }
226
227 #[inline]
229 pub fn is_null(&self) -> bool {
230 self.tag() == ValueTag::Null
231 }
232
233 #[inline]
235 pub fn is_inline(&self) -> bool {
236 matches!(
237 self.tag(),
238 ValueTag::Null
239 | ValueTag::Bool
240 | ValueTag::SmallInt
241 | ValueTag::InlineString
242 | ValueTag::InlineBytes
243 )
244 }
245
246 #[inline]
248 pub fn as_bool(&self) -> Option<bool> {
249 if self.tag() == ValueTag::Bool {
250 Some((self.bits & 1) != 0)
251 } else {
252 None
253 }
254 }
255
256 #[inline]
258 pub fn as_int(&self) -> Option<i64> {
259 if self.tag() == ValueTag::SmallInt {
260 let raw = (self.bits & INLINE_DATA_MASK) as i64;
262 let sign_bit = 1i64 << 55;
263 Some(if raw & sign_bit != 0 {
264 raw | !INLINE_DATA_MASK as i64
265 } else {
266 raw
267 })
268 } else {
269 None
270 }
271 }
272
273 pub fn as_float(&self) -> Option<f64> {
275 if self.tag() == ValueTag::Float {
276 self.heap.as_ref().map(|h| {
277 let bytes: [u8; 8] = h.as_ref().try_into().unwrap_or([0; 8]);
278 f64::from_le_bytes(bytes)
279 })
280 } else {
281 None
282 }
283 }
284
285 #[inline]
287 fn inline_len(&self) -> usize {
288 ((self.bits >> INLINE_LEN_SHIFT) & INLINE_LEN_MASK) as usize
289 }
290
291 pub fn as_str(&self) -> Option<String> {
295 match self.tag() {
296 ValueTag::InlineString => self
297 .inline_bytes_copy()
298 .and_then(|bytes| String::from_utf8(bytes).ok()),
299 ValueTag::HeapString => self
300 .heap
301 .as_ref()
302 .and_then(|h| std::str::from_utf8(h).ok().map(|s| s.to_owned())),
303 _ => None,
304 }
305 }
306
307 pub fn as_heap_str(&self) -> Option<&str> {
309 match self.tag() {
310 ValueTag::HeapString => self.heap.as_ref().and_then(|h| std::str::from_utf8(h).ok()),
311 _ => None,
312 }
313 }
314
315 pub fn as_bytes(&self) -> Option<&[u8]> {
317 match self.tag() {
318 ValueTag::InlineBytes => {
319 None
321 }
322 ValueTag::HeapBytes => self.heap.as_ref().map(|h| h.as_ref()),
323 _ => None,
324 }
325 }
326
327 pub fn inline_bytes_copy(&self) -> Option<Vec<u8>> {
329 match self.tag() {
330 ValueTag::InlineBytes | ValueTag::InlineString => {
331 let len = self.inline_len();
332 let bytes = (self.bits & INLINE_DATA_MASK).to_le_bytes();
333 Some(bytes[..len].to_vec())
334 }
335 _ => None,
336 }
337 }
338
339 pub fn encoded_size(&self) -> usize {
341 8 + self.heap.as_ref().map(|h| h.len()).unwrap_or(0)
342 }
343
344 pub fn to_bytes(&self) -> Vec<u8> {
346 let mut buf = Vec::with_capacity(self.encoded_size());
347 buf.extend_from_slice(&self.bits.to_le_bytes());
348 if let Some(ref heap) = self.heap {
349 buf.extend_from_slice(heap);
350 }
351 buf
352 }
353
354 pub fn from_bytes(data: &[u8]) -> Option<Self> {
356 if data.len() < 8 {
357 return None;
358 }
359
360 let bits = u64::from_le_bytes(data[..8].try_into().ok()?);
361 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
362
363 let heap = match tag {
364 ValueTag::HeapString | ValueTag::HeapBytes => {
365 let len = (bits & 0x1FFF_FFFF) as usize;
366 if data.len() < 8 + len {
367 return None;
368 }
369 Some(data[8..8 + len].to_vec().into_boxed_slice())
370 }
371 ValueTag::Float => {
372 if data.len() >= 16 {
373 Some(data[8..16].to_vec().into_boxed_slice())
374 } else {
375 None
376 }
377 }
378 _ => None,
379 };
380
381 Some(Self { bits, heap })
382 }
383}
384
385impl Default for PolymorphicValue {
386 fn default() -> Self {
387 Self::null()
388 }
389}
390
391impl std::fmt::Debug for PolymorphicValue {
392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393 match self.tag() {
394 ValueTag::Null => write!(f, "Null"),
395 ValueTag::Bool => write!(f, "Bool({})", self.as_bool().unwrap_or(false)),
396 ValueTag::SmallInt => write!(f, "Int({})", self.as_int().unwrap_or(0)),
397 ValueTag::InlineString | ValueTag::HeapString => {
398 if let Some(s) = self.as_str() {
399 write!(f, "String({:?})", s)
400 } else if let Some(b) = self.inline_bytes_copy() {
401 write!(f, "String({:?})", String::from_utf8_lossy(&b))
402 } else {
403 write!(f, "String(<invalid>)")
404 }
405 }
406 ValueTag::InlineBytes | ValueTag::HeapBytes => {
407 write!(f, "Bytes({} bytes)", self.inline_len())
408 }
409 ValueTag::Float => write!(f, "Float({:?})", self.as_float()),
410 }
411 }
412}
413
414pub struct AtomicPolymorphicValue {
423 bits: AtomicU64,
424}
425
426impl AtomicPolymorphicValue {
427 pub fn null() -> Self {
429 Self {
430 bits: AtomicU64::new((ValueTag::Null as u64) << TAG_SHIFT),
431 }
432 }
433
434 pub fn from_inline(v: &PolymorphicValue) -> Option<Self> {
436 if v.is_inline() {
437 Some(Self {
438 bits: AtomicU64::new(v.bits),
439 })
440 } else {
441 None
442 }
443 }
444
445 #[inline]
447 pub fn load(&self, order: Ordering) -> u64 {
448 self.bits.load(order)
449 }
450
451 #[inline]
453 pub fn store(&self, value: &PolymorphicValue, order: Ordering) {
454 debug_assert!(
455 value.is_inline(),
456 "AtomicPolymorphicValue only supports inline values"
457 );
458 self.bits.store(value.bits, order);
459 }
460
461 #[inline]
463 pub fn compare_exchange(
464 &self,
465 current: &PolymorphicValue,
466 new: &PolymorphicValue,
467 success: Ordering,
468 failure: Ordering,
469 ) -> Result<u64, u64> {
470 debug_assert!(
471 new.is_inline(),
472 "AtomicPolymorphicValue only supports inline values"
473 );
474 self.bits
475 .compare_exchange(current.bits, new.bits, success, failure)
476 }
477
478 #[inline]
480 pub fn tag(&self) -> ValueTag {
481 let bits = self.bits.load(Ordering::Relaxed);
482 ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07).unwrap_or(ValueTag::Null)
483 }
484
485 #[inline]
487 pub fn try_as_int(&self, order: Ordering) -> Option<i64> {
488 let bits = self.bits.load(order);
489 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
490
491 if tag == ValueTag::SmallInt {
492 let raw = (bits & INLINE_DATA_MASK) as i64;
493 let sign_bit = 1i64 << 55;
494 Some(if raw & sign_bit != 0 {
495 raw | !INLINE_DATA_MASK as i64
496 } else {
497 raw
498 })
499 } else {
500 None
501 }
502 }
503
504 pub fn fetch_add(&self, delta: i64, order: Ordering) -> Option<i64> {
506 loop {
507 let bits = self.bits.load(Ordering::Acquire);
508 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
509
510 if tag != ValueTag::SmallInt {
511 return None;
512 }
513
514 let current = {
515 let raw = (bits & INLINE_DATA_MASK) as i64;
516 let sign_bit = 1i64 << 55;
517 if raw & sign_bit != 0 {
518 raw | !INLINE_DATA_MASK as i64
519 } else {
520 raw
521 }
522 };
523
524 let new_value = current.wrapping_add(delta);
525 let new_bits = ((ValueTag::SmallInt as u64) << TAG_SHIFT)
526 | ((new_value as u64) & INLINE_DATA_MASK);
527
528 if self
529 .bits
530 .compare_exchange_weak(bits, new_bits, order, Ordering::Relaxed)
531 .is_ok()
532 {
533 return Some(current);
534 }
535 }
536 }
537}
538
539pub struct CompressedValueArray {
547 data: Vec<u8>,
549 len: usize,
551}
552
553impl CompressedValueArray {
554 pub fn from_values(values: &[PolymorphicValue]) -> Self {
556 let mut data = Vec::new();
557 let mut i = 0;
558
559 while i < values.len() {
560 let value = &values[i];
561
562 let mut run_len = 1usize;
564 while i + run_len < values.len() && run_len < 255 {
565 if Self::values_equal(&values[i + run_len], value) {
566 run_len += 1;
567 } else {
568 break;
569 }
570 }
571
572 if run_len > 1 {
574 data.push(0xFF); data.push(run_len as u8);
576 } else {
577 data.push(0xFE); }
579 data.extend_from_slice(&value.to_bytes());
580
581 i += run_len;
582 }
583
584 Self {
585 data,
586 len: values.len(),
587 }
588 }
589
590 fn values_equal(a: &PolymorphicValue, b: &PolymorphicValue) -> bool {
592 if a.tag() != b.tag() || a.bits != b.bits {
593 return false;
594 }
595 match (&a.heap, &b.heap) {
596 (Some(ha), Some(hb)) => ha == hb,
597 (None, None) => true,
598 _ => false,
599 }
600 }
601
602 pub fn len(&self) -> usize {
604 self.len
605 }
606
607 pub fn is_empty(&self) -> bool {
609 self.len == 0
610 }
611
612 pub fn compressed_size(&self) -> usize {
614 self.data.len()
615 }
616
617 pub fn decompress(&self) -> Vec<PolymorphicValue> {
619 let mut values = Vec::with_capacity(self.len);
620 let mut i = 0;
621
622 while i < self.data.len() {
623 let marker = self.data[i];
624 i += 1;
625
626 let (run_len, value) = if marker == 0xFF {
627 let run_len = self.data[i] as usize;
629 i += 1;
630 let value = PolymorphicValue::from_bytes(&self.data[i..]);
631 if let Some(v) = value {
632 i += v.encoded_size();
633 (run_len, v)
634 } else {
635 break;
636 }
637 } else if marker == 0xFE {
638 let value = PolymorphicValue::from_bytes(&self.data[i..]);
640 if let Some(v) = value {
641 i += v.encoded_size();
642 (1, v)
643 } else {
644 break;
645 }
646 } else {
647 break;
648 };
649
650 for _ in 0..run_len {
651 values.push(value.clone());
652 }
653 }
654
655 values
656 }
657}
658
659#[cfg(test)]
660mod tests {
661 use super::*;
662
663 #[test]
664 fn test_null_value() {
665 let v = PolymorphicValue::null();
666 assert!(v.is_null());
667 assert!(v.is_inline());
668 assert_eq!(v.encoded_size(), 8);
669 }
670
671 #[test]
672 fn test_bool_value() {
673 let t = PolymorphicValue::bool(true);
674 let f = PolymorphicValue::bool(false);
675
676 assert_eq!(t.as_bool(), Some(true));
677 assert_eq!(f.as_bool(), Some(false));
678 assert!(t.is_inline());
679 assert!(f.is_inline());
680 }
681
682 #[test]
683 fn test_int_value() {
684 let v1 = PolymorphicValue::int(42);
685 let v2 = PolymorphicValue::int(-100);
686 let v3 = PolymorphicValue::int(0);
687 let v4 = PolymorphicValue::int(i64::MAX >> 8); assert_eq!(v1.as_int(), Some(42));
690 assert_eq!(v2.as_int(), Some(-100));
691 assert_eq!(v3.as_int(), Some(0));
692 assert_eq!(v4.as_int(), Some(i64::MAX >> 8));
693
694 assert!(v1.is_inline());
695 assert!(v2.is_inline());
696 }
697
698 #[test]
699 fn test_inline_string() {
700 let v = PolymorphicValue::string("hello");
701 assert!(v.is_inline());
702 assert_eq!(v.tag(), ValueTag::InlineString);
703
704 let bytes = v.inline_bytes_copy().unwrap();
705 assert_eq!(&bytes, b"hello");
706 }
707
708 #[test]
709 fn test_heap_string() {
710 let long_str = "This is a string that is longer than 7 bytes";
711 let v = PolymorphicValue::string(long_str);
712
713 assert!(!v.is_inline());
714 assert_eq!(v.tag(), ValueTag::HeapString);
715 assert_eq!(v.as_str(), Some(long_str.to_string()));
716 }
717
718 #[test]
719 #[allow(clippy::approx_constant)] fn test_float_value() {
721 let v = PolymorphicValue::float(3.14159);
722 assert_eq!(v.tag(), ValueTag::Float);
723
724 let f = v.as_float().unwrap();
725 assert!((f - 3.14159).abs() < 1e-10);
726 }
727
728 #[test]
729 fn test_serialization() {
730 let values = vec![
731 PolymorphicValue::null(),
732 PolymorphicValue::bool(true),
733 PolymorphicValue::int(42),
734 PolymorphicValue::string("hi"),
735 PolymorphicValue::string("This is a longer string"),
736 ];
737
738 for v in values {
739 let bytes = v.to_bytes();
740 let restored = PolymorphicValue::from_bytes(&bytes).unwrap();
741
742 assert_eq!(v.tag(), restored.tag());
743 assert_eq!(v.bits, restored.bits);
744 }
745 }
746
747 #[test]
748 fn test_atomic_value() {
749 let atomic = AtomicPolymorphicValue::from_inline(&PolymorphicValue::int(0)).unwrap();
750
751 let old = atomic.fetch_add(5, Ordering::SeqCst);
753 assert_eq!(old, Some(0));
754
755 let current = atomic.try_as_int(Ordering::Acquire);
756 assert_eq!(current, Some(5));
757 }
758
759 #[test]
760 fn test_compressed_array() {
761 let values: Vec<_> = (0..100)
763 .map(|i| {
764 if i < 50 {
765 PolymorphicValue::int(42)
766 } else {
767 PolymorphicValue::int(i as i64)
768 }
769 })
770 .collect();
771
772 let compressed = CompressedValueArray::from_values(&values);
773 assert_eq!(compressed.len(), 100);
774
775 let uncompressed_size = 100 * 8; assert!(compressed.compressed_size() < uncompressed_size);
778
779 let restored = compressed.decompress();
781 assert_eq!(restored.len(), 100);
782
783 for (i, v) in restored.iter().enumerate() {
784 let expected = if i < 50 { 42 } else { i as i64 };
785 assert_eq!(v.as_int(), Some(expected));
786 }
787 }
788
789 #[test]
790 fn test_int_edge_cases() {
791 let max_inline = (1i64 << 55) - 1;
793 let min_inline = -(1i64 << 55);
794
795 let v1 = PolymorphicValue::int(max_inline);
796 let v2 = PolymorphicValue::int(min_inline);
797
798 assert_eq!(v1.as_int(), Some(max_inline));
799 assert_eq!(v2.as_int(), Some(min_inline));
800 }
801}