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)
154 | ((v as u64) & INLINE_DATA_MASK);
155 Self { bits, heap: None }
156 } else {
157 let bytes = v.to_le_bytes();
159 Self::heap_bytes(&bytes, ValueTag::HeapBytes)
160 }
161 }
162
163 pub fn string(s: &str) -> Self {
167 let bytes = s.as_bytes();
168 if bytes.len() <= MAX_INLINE_SIZE {
169 Self::inline_bytes(bytes, ValueTag::InlineString)
170 } else {
171 Self::heap_bytes(bytes, ValueTag::HeapString)
172 }
173 }
174
175 pub fn bytes(b: &[u8]) -> Self {
179 if b.len() <= MAX_INLINE_SIZE {
180 Self::inline_bytes(b, ValueTag::InlineBytes)
181 } else {
182 Self::heap_bytes(b, ValueTag::HeapBytes)
183 }
184 }
185
186 #[inline]
188 pub fn float(v: f64) -> Self {
189 let bits = v.to_bits();
191 let packed = ((ValueTag::Float as u64) << TAG_SHIFT) | (bits & INLINE_DATA_MASK);
192 Self { bits: packed, heap: Some(Box::new(bits.to_le_bytes())) }
193 }
194
195 fn inline_bytes(data: &[u8], tag: ValueTag) -> Self {
197 debug_assert!(data.len() <= MAX_INLINE_SIZE);
198
199 let mut packed = 0u64;
200 for (i, &byte) in data.iter().enumerate() {
201 packed |= (byte as u64) << (i * 8);
202 }
203
204 let bits = ((tag as u64) << TAG_SHIFT)
205 | ((data.len() as u64) << INLINE_LEN_SHIFT)
206 | 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 { bits, heap: Some(heap) }
216 }
217
218 #[inline]
220 pub fn tag(&self) -> ValueTag {
221 ValueTag::from_u8((self.bits >> TAG_SHIFT) as u8 & 0x07).unwrap_or(ValueTag::Null)
222 }
223
224 #[inline]
226 pub fn is_null(&self) -> bool {
227 self.tag() == ValueTag::Null
228 }
229
230 #[inline]
232 pub fn is_inline(&self) -> bool {
233 matches!(
234 self.tag(),
235 ValueTag::Null | ValueTag::Bool | ValueTag::SmallInt
236 | ValueTag::InlineString | ValueTag::InlineBytes
237 )
238 }
239
240 #[inline]
242 pub fn as_bool(&self) -> Option<bool> {
243 if self.tag() == ValueTag::Bool {
244 Some((self.bits & 1) != 0)
245 } else {
246 None
247 }
248 }
249
250 #[inline]
252 pub fn as_int(&self) -> Option<i64> {
253 if self.tag() == ValueTag::SmallInt {
254 let raw = (self.bits & INLINE_DATA_MASK) as i64;
256 let sign_bit = 1i64 << 55;
257 Some(if raw & sign_bit != 0 {
258 raw | !INLINE_DATA_MASK as i64
259 } else {
260 raw
261 })
262 } else {
263 None
264 }
265 }
266
267 pub fn as_float(&self) -> Option<f64> {
269 if self.tag() == ValueTag::Float {
270 self.heap.as_ref().map(|h| {
271 let bytes: [u8; 8] = h.as_ref().try_into().unwrap_or([0; 8]);
272 f64::from_le_bytes(bytes)
273 })
274 } else {
275 None
276 }
277 }
278
279 #[inline]
281 fn inline_len(&self) -> usize {
282 ((self.bits >> INLINE_LEN_SHIFT) & INLINE_LEN_MASK) as usize
283 }
284
285 pub fn as_str(&self) -> Option<String> {
289 match self.tag() {
290 ValueTag::InlineString => {
291 self.inline_bytes_copy()
292 .and_then(|bytes| String::from_utf8(bytes).ok())
293 }
294 ValueTag::HeapString => {
295 self.heap.as_ref().and_then(|h| std::str::from_utf8(h).ok().map(|s| s.to_owned()))
296 }
297 _ => None,
298 }
299 }
300
301 pub fn as_heap_str(&self) -> Option<&str> {
303 match self.tag() {
304 ValueTag::HeapString => {
305 self.heap.as_ref().and_then(|h| std::str::from_utf8(h).ok())
306 }
307 _ => None,
308 }
309 }
310
311 pub fn as_bytes(&self) -> Option<&[u8]> {
313 match self.tag() {
314 ValueTag::InlineBytes => {
315 None
317 }
318 ValueTag::HeapBytes => {
319 self.heap.as_ref().map(|h| h.as_ref())
320 }
321 _ => None,
322 }
323 }
324
325 pub fn inline_bytes_copy(&self) -> Option<Vec<u8>> {
327 match self.tag() {
328 ValueTag::InlineBytes | ValueTag::InlineString => {
329 let len = self.inline_len();
330 let bytes = (self.bits & INLINE_DATA_MASK).to_le_bytes();
331 Some(bytes[..len].to_vec())
332 }
333 _ => None,
334 }
335 }
336
337 pub fn encoded_size(&self) -> usize {
339 8 + self.heap.as_ref().map(|h| h.len()).unwrap_or(0)
340 }
341
342 pub fn to_bytes(&self) -> Vec<u8> {
344 let mut buf = Vec::with_capacity(self.encoded_size());
345 buf.extend_from_slice(&self.bits.to_le_bytes());
346 if let Some(ref heap) = self.heap {
347 buf.extend_from_slice(heap);
348 }
349 buf
350 }
351
352 pub fn from_bytes(data: &[u8]) -> Option<Self> {
354 if data.len() < 8 {
355 return None;
356 }
357
358 let bits = u64::from_le_bytes(data[..8].try_into().ok()?);
359 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
360
361 let heap = match tag {
362 ValueTag::HeapString | ValueTag::HeapBytes => {
363 let len = (bits & 0x1FFF_FFFF) as usize;
364 if data.len() < 8 + len {
365 return None;
366 }
367 Some(data[8..8 + len].to_vec().into_boxed_slice())
368 }
369 ValueTag::Float => {
370 if data.len() >= 16 {
371 Some(data[8..16].to_vec().into_boxed_slice())
372 } else {
373 None
374 }
375 }
376 _ => None,
377 };
378
379 Some(Self { bits, heap })
380 }
381}
382
383impl Default for PolymorphicValue {
384 fn default() -> Self {
385 Self::null()
386 }
387}
388
389impl std::fmt::Debug for PolymorphicValue {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 match self.tag() {
392 ValueTag::Null => write!(f, "Null"),
393 ValueTag::Bool => write!(f, "Bool({})", self.as_bool().unwrap_or(false)),
394 ValueTag::SmallInt => write!(f, "Int({})", self.as_int().unwrap_or(0)),
395 ValueTag::InlineString | ValueTag::HeapString => {
396 if let Some(s) = self.as_str() {
397 write!(f, "String({:?})", s)
398 } else if let Some(b) = self.inline_bytes_copy() {
399 write!(f, "String({:?})", String::from_utf8_lossy(&b))
400 } else {
401 write!(f, "String(<invalid>)")
402 }
403 }
404 ValueTag::InlineBytes | ValueTag::HeapBytes => {
405 write!(f, "Bytes({} bytes)", self.inline_len())
406 }
407 ValueTag::Float => write!(f, "Float({:?})", self.as_float()),
408 }
409 }
410}
411
412pub struct AtomicPolymorphicValue {
421 bits: AtomicU64,
422}
423
424impl AtomicPolymorphicValue {
425 pub fn null() -> Self {
427 Self {
428 bits: AtomicU64::new((ValueTag::Null as u64) << TAG_SHIFT),
429 }
430 }
431
432 pub fn from_inline(v: &PolymorphicValue) -> Option<Self> {
434 if v.is_inline() {
435 Some(Self {
436 bits: AtomicU64::new(v.bits),
437 })
438 } else {
439 None
440 }
441 }
442
443 #[inline]
445 pub fn load(&self, order: Ordering) -> u64 {
446 self.bits.load(order)
447 }
448
449 #[inline]
451 pub fn store(&self, value: &PolymorphicValue, order: Ordering) {
452 debug_assert!(value.is_inline(), "AtomicPolymorphicValue only supports inline values");
453 self.bits.store(value.bits, order);
454 }
455
456 #[inline]
458 pub fn compare_exchange(
459 &self,
460 current: &PolymorphicValue,
461 new: &PolymorphicValue,
462 success: Ordering,
463 failure: Ordering,
464 ) -> Result<u64, u64> {
465 debug_assert!(new.is_inline(), "AtomicPolymorphicValue only supports inline values");
466 self.bits.compare_exchange(current.bits, new.bits, success, failure)
467 }
468
469 #[inline]
471 pub fn tag(&self) -> ValueTag {
472 let bits = self.bits.load(Ordering::Relaxed);
473 ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07).unwrap_or(ValueTag::Null)
474 }
475
476 #[inline]
478 pub fn try_as_int(&self, order: Ordering) -> Option<i64> {
479 let bits = self.bits.load(order);
480 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
481
482 if tag == ValueTag::SmallInt {
483 let raw = (bits & INLINE_DATA_MASK) as i64;
484 let sign_bit = 1i64 << 55;
485 Some(if raw & sign_bit != 0 {
486 raw | !INLINE_DATA_MASK as i64
487 } else {
488 raw
489 })
490 } else {
491 None
492 }
493 }
494
495 pub fn fetch_add(&self, delta: i64, order: Ordering) -> Option<i64> {
497 loop {
498 let bits = self.bits.load(Ordering::Acquire);
499 let tag = ValueTag::from_u8((bits >> TAG_SHIFT) as u8 & 0x07)?;
500
501 if tag != ValueTag::SmallInt {
502 return None;
503 }
504
505 let current = {
506 let raw = (bits & INLINE_DATA_MASK) as i64;
507 let sign_bit = 1i64 << 55;
508 if raw & sign_bit != 0 {
509 raw | !INLINE_DATA_MASK as i64
510 } else {
511 raw
512 }
513 };
514
515 let new_value = current.wrapping_add(delta);
516 let new_bits = ((ValueTag::SmallInt as u64) << TAG_SHIFT)
517 | ((new_value as u64) & INLINE_DATA_MASK);
518
519 if self.bits.compare_exchange_weak(bits, new_bits, order, Ordering::Relaxed).is_ok() {
520 return Some(current);
521 }
522 }
523 }
524}
525
526pub struct CompressedValueArray {
534 data: Vec<u8>,
536 len: usize,
538}
539
540impl CompressedValueArray {
541 pub fn from_values(values: &[PolymorphicValue]) -> Self {
543 let mut data = Vec::new();
544 let mut i = 0;
545
546 while i < values.len() {
547 let value = &values[i];
548
549 let mut run_len = 1usize;
551 while i + run_len < values.len() && run_len < 255 {
552 if Self::values_equal(&values[i + run_len], value) {
553 run_len += 1;
554 } else {
555 break;
556 }
557 }
558
559 if run_len > 1 {
561 data.push(0xFF); data.push(run_len as u8);
563 } else {
564 data.push(0xFE); }
566 data.extend_from_slice(&value.to_bytes());
567
568 i += run_len;
569 }
570
571 Self {
572 data,
573 len: values.len(),
574 }
575 }
576
577 fn values_equal(a: &PolymorphicValue, b: &PolymorphicValue) -> bool {
579 if a.tag() != b.tag() || a.bits != b.bits {
580 return false;
581 }
582 match (&a.heap, &b.heap) {
583 (Some(ha), Some(hb)) => ha == hb,
584 (None, None) => true,
585 _ => false,
586 }
587 }
588
589 pub fn len(&self) -> usize {
591 self.len
592 }
593
594 pub fn is_empty(&self) -> bool {
596 self.len == 0
597 }
598
599 pub fn compressed_size(&self) -> usize {
601 self.data.len()
602 }
603
604 pub fn decompress(&self) -> Vec<PolymorphicValue> {
606 let mut values = Vec::with_capacity(self.len);
607 let mut i = 0;
608
609 while i < self.data.len() {
610 let marker = self.data[i];
611 i += 1;
612
613 let (run_len, value) = if marker == 0xFF {
614 let run_len = self.data[i] as usize;
616 i += 1;
617 let value = PolymorphicValue::from_bytes(&self.data[i..]);
618 if let Some(v) = value {
619 i += v.encoded_size();
620 (run_len, v)
621 } else {
622 break;
623 }
624 } else if marker == 0xFE {
625 let value = PolymorphicValue::from_bytes(&self.data[i..]);
627 if let Some(v) = value {
628 i += v.encoded_size();
629 (1, v)
630 } else {
631 break;
632 }
633 } else {
634 break;
635 };
636
637 for _ in 0..run_len {
638 values.push(value.clone());
639 }
640 }
641
642 values
643 }
644}
645
646#[cfg(test)]
647mod tests {
648 use super::*;
649
650 #[test]
651 fn test_null_value() {
652 let v = PolymorphicValue::null();
653 assert!(v.is_null());
654 assert!(v.is_inline());
655 assert_eq!(v.encoded_size(), 8);
656 }
657
658 #[test]
659 fn test_bool_value() {
660 let t = PolymorphicValue::bool(true);
661 let f = PolymorphicValue::bool(false);
662
663 assert_eq!(t.as_bool(), Some(true));
664 assert_eq!(f.as_bool(), Some(false));
665 assert!(t.is_inline());
666 assert!(f.is_inline());
667 }
668
669 #[test]
670 fn test_int_value() {
671 let v1 = PolymorphicValue::int(42);
672 let v2 = PolymorphicValue::int(-100);
673 let v3 = PolymorphicValue::int(0);
674 let v4 = PolymorphicValue::int(i64::MAX >> 8); assert_eq!(v1.as_int(), Some(42));
677 assert_eq!(v2.as_int(), Some(-100));
678 assert_eq!(v3.as_int(), Some(0));
679 assert_eq!(v4.as_int(), Some(i64::MAX >> 8));
680
681 assert!(v1.is_inline());
682 assert!(v2.is_inline());
683 }
684
685 #[test]
686 fn test_inline_string() {
687 let v = PolymorphicValue::string("hello");
688 assert!(v.is_inline());
689 assert_eq!(v.tag(), ValueTag::InlineString);
690
691 let bytes = v.inline_bytes_copy().unwrap();
692 assert_eq!(&bytes, b"hello");
693 }
694
695 #[test]
696 fn test_heap_string() {
697 let long_str = "This is a string that is longer than 7 bytes";
698 let v = PolymorphicValue::string(long_str);
699
700 assert!(!v.is_inline());
701 assert_eq!(v.tag(), ValueTag::HeapString);
702 assert_eq!(v.as_str(), Some(long_str.to_string()));
703 }
704
705 #[test]
706 fn test_float_value() {
707 let v = PolymorphicValue::float(3.14159);
708 assert_eq!(v.tag(), ValueTag::Float);
709
710 let f = v.as_float().unwrap();
711 assert!((f - 3.14159).abs() < 1e-10);
712 }
713
714 #[test]
715 fn test_serialization() {
716 let values = vec![
717 PolymorphicValue::null(),
718 PolymorphicValue::bool(true),
719 PolymorphicValue::int(42),
720 PolymorphicValue::string("hi"),
721 PolymorphicValue::string("This is a longer string"),
722 ];
723
724 for v in values {
725 let bytes = v.to_bytes();
726 let restored = PolymorphicValue::from_bytes(&bytes).unwrap();
727
728 assert_eq!(v.tag(), restored.tag());
729 assert_eq!(v.bits, restored.bits);
730 }
731 }
732
733 #[test]
734 fn test_atomic_value() {
735 let atomic = AtomicPolymorphicValue::from_inline(&PolymorphicValue::int(0)).unwrap();
736
737 let old = atomic.fetch_add(5, Ordering::SeqCst);
739 assert_eq!(old, Some(0));
740
741 let current = atomic.try_as_int(Ordering::Acquire);
742 assert_eq!(current, Some(5));
743 }
744
745 #[test]
746 fn test_compressed_array() {
747 let values: Vec<_> = (0..100)
749 .map(|i| {
750 if i < 50 {
751 PolymorphicValue::int(42)
752 } else {
753 PolymorphicValue::int(i as i64)
754 }
755 })
756 .collect();
757
758 let compressed = CompressedValueArray::from_values(&values);
759 assert_eq!(compressed.len(), 100);
760
761 let uncompressed_size = 100 * 8; assert!(compressed.compressed_size() < uncompressed_size);
764
765 let restored = compressed.decompress();
767 assert_eq!(restored.len(), 100);
768
769 for (i, v) in restored.iter().enumerate() {
770 let expected = if i < 50 { 42 } else { i as i64 };
771 assert_eq!(v.as_int(), Some(expected));
772 }
773 }
774
775 #[test]
776 fn test_int_edge_cases() {
777 let max_inline = (1i64 << 55) - 1;
779 let min_inline = -(1i64 << 55);
780
781 let v1 = PolymorphicValue::int(max_inline);
782 let v2 = PolymorphicValue::int(min_inline);
783
784 assert_eq!(v1.as_int(), Some(max_inline));
785 assert_eq!(v2.as_int(), Some(min_inline));
786 }
787}