Skip to main content

clt_database/
types.rs

1use crate::turso_debug_assert;
2use branches::{mark_unlikely, unlikely};
3use either::Either;
4use turso_ext::{AggCtx, ContextDestructor, FinalizeFunction, StepFunction, ValueDestructor};
5use turso_parser::ast::SortOrder;
6
7use crate::alloc::*;
8use crate::error::LimboError;
9use crate::ext::{ExtValue, ExtValueType};
10use crate::index_method::IndexMethodCursor;
11use crate::numeric::format_float;
12use crate::numeric::nonnan::NonNan;
13use crate::numeric::Numeric;
14use crate::pseudo::PseudoCursor;
15use crate::schema::Index;
16use crate::storage::btree::CursorTrait;
17use crate::storage::sqlite3_ondisk::{read_integer, read_value, read_varint, write_varint};
18use crate::translate::collate::CollationSeq;
19use crate::translate::plan::IterationDirection;
20use crate::vdbe::sorter::Sorter;
21use crate::vdbe::Register;
22use crate::vtab::VirtualTableCursor;
23use crate::{Completion, CompletionError, Result, IO};
24use std::borrow::{Borrow, Cow};
25use std::cell::Cell;
26use std::fmt::{Debug, Display};
27use std::future::Future;
28use std::iter::{FusedIterator, Peekable};
29use std::ops::Deref;
30use std::task::{Poll, Waker};
31
32/// SQLite by default uses 2000 as maximum numbers in a row.
33/// It controlld by the constant called SQLITE_MAX_COLUMN
34/// But the hard limit of number of columns is 32,767 columns i16::MAX
35/// const MAX_COLUMN: usize = 2000;
36
37#[derive(Debug, Clone, Copy, PartialEq)]
38pub enum ValueType {
39    Null,
40    Integer,
41    Float,
42    Text,
43    Blob,
44    Error,
45}
46
47impl Display for ValueType {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        let value = match self {
50            Self::Null => "NULL",
51            Self::Integer => "INT",
52            Self::Float => "REAL",
53            Self::Blob => "BLOB",
54            Self::Text => "TEXT",
55            Self::Error => "ERROR",
56        };
57        write!(f, "{value}")
58    }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq)]
62#[cfg_attr(clt_turso_feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63pub enum TextSubtype {
64    Text,
65    #[cfg(clt_turso_feature = "json")]
66    Json,
67}
68
69#[derive(Debug, Clone)]
70#[cfg_attr(clt_turso_feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71pub struct Text {
72    pub value: Cow<'static, str>,
73    pub subtype: TextSubtype,
74}
75
76impl Display for Text {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        write!(f, "{}", self.as_str())
79    }
80}
81
82impl Text {
83    pub fn new(value: impl Into<Cow<'static, str>>) -> Self {
84        Self {
85            value: value.into(),
86            subtype: TextSubtype::Text,
87        }
88    }
89    #[cfg(clt_turso_feature = "json")]
90    pub fn json(value: String) -> Self {
91        Self {
92            value: value.into(),
93            subtype: TextSubtype::Json,
94        }
95    }
96
97    pub fn as_str(&self) -> &str {
98        &self.value
99    }
100}
101
102#[derive(Debug, Clone, Copy)]
103pub struct TextRef<'a> {
104    pub value: &'a str,
105    pub subtype: TextSubtype,
106}
107
108impl<'a> TextRef<'a> {
109    pub fn new(value: &'a str, subtype: TextSubtype) -> Self {
110        Self { value, subtype }
111    }
112
113    #[inline]
114    pub fn as_str(&self) -> &'a str {
115        self.value
116    }
117}
118
119impl<'a> Borrow<str> for TextRef<'a> {
120    #[inline]
121    fn borrow(&self) -> &str {
122        self.as_str()
123    }
124}
125
126impl<'a> Deref for TextRef<'a> {
127    type Target = str;
128
129    #[inline]
130    fn deref(&self) -> &Self::Target {
131        self.as_str()
132    }
133}
134
135pub trait Extendable<T> {
136    fn do_extend(&mut self, other: &T) -> Result<()>;
137}
138
139impl<T: AnyText> Extendable<T> for Text {
140    #[inline(always)]
141    fn do_extend(&mut self, other: &T) -> Result<()> {
142        let other_str = other.as_ref();
143        match &mut self.value {
144            Cow::Owned(s) => {
145                let needed = other_str.len();
146                if s.capacity() >= needed {
147                    // SAFETY: capacity >= needed, source is valid UTF-8
148                    turso_debug_assert!(
149                        s.as_ptr().wrapping_add(s.len()) <= other_str.as_ptr()
150                            || other_str.as_ptr().wrapping_add(other_str.len()) <= s.as_ptr(),
151                        "source and destination ranges must not overlap"
152                    );
153                    unsafe {
154                        std::ptr::copy_nonoverlapping(other_str.as_ptr(), s.as_mut_ptr(), needed);
155                        s.as_mut_vec().set_len(needed);
156                    }
157                } else {
158                    other_str.clone_into(s);
159                }
160            }
161            Cow::Borrowed(_) => {
162                self.value = Cow::Owned(other_str.to_owned());
163            }
164        }
165        self.subtype = other.subtype();
166        Ok(())
167    }
168}
169
170impl<T: AnyBlob> Extendable<T> for std::vec::Vec<u8> {
171    #[inline(always)]
172    fn do_extend(&mut self, other: &T) -> Result<()> {
173        let other_slice = other.as_slice();
174        let needed = other_slice.len();
175        if self.capacity() >= needed {
176            // SAFETY: capacity >= needed
177            turso_debug_assert!(
178                self.as_ptr().wrapping_add(self.len()) <= other_slice.as_ptr()
179                    || other_slice.as_ptr().wrapping_add(other_slice.len()) <= self.as_ptr(),
180                "source and destination ranges must not overlap"
181            );
182            unsafe {
183                std::ptr::copy_nonoverlapping(other_slice.as_ptr(), self.as_mut_ptr(), needed);
184                self.set_len(needed);
185            }
186        } else {
187            self.clear();
188            // Reserve mores space to extend the slice
189            self.try_reserve(self.len().abs_diff(needed))?;
190            self.extend_from_slice(other_slice);
191        }
192        Ok(())
193    }
194}
195
196pub trait AnyText: AsRef<str> {
197    fn subtype(&self) -> TextSubtype;
198}
199
200impl AnyText for Text {
201    fn subtype(&self) -> TextSubtype {
202        self.subtype
203    }
204}
205
206impl AnyText for &str {
207    fn subtype(&self) -> TextSubtype {
208        TextSubtype::Text
209    }
210}
211
212pub trait AnyBlob {
213    fn as_slice(&self) -> &[u8];
214}
215
216impl AnyBlob for std::vec::Vec<u8> {
217    fn as_slice(&self) -> &[u8] {
218        self.as_slice()
219    }
220}
221
222impl AnyBlob for &[u8] {
223    fn as_slice(&self) -> &[u8] {
224        self
225    }
226}
227
228impl AsRef<str> for Text {
229    fn as_ref(&self) -> &str {
230        self.as_str()
231    }
232}
233
234impl From<&str> for Text {
235    fn from(value: &str) -> Self {
236        Text {
237            value: value.to_owned().into(),
238            subtype: TextSubtype::Text,
239        }
240    }
241}
242
243impl From<String> for Text {
244    fn from(value: String) -> Self {
245        Text {
246            value: Cow::from(value),
247            subtype: TextSubtype::Text,
248        }
249    }
250}
251
252impl From<Text> for String {
253    fn from(value: Text) -> Self {
254        value.value.into_owned()
255    }
256}
257
258// Note: Struct and union values are serialized directly in VDBE instructions
259// (MakeArray for structs, op_union_pack for unions) using the SQLite record format for structs
260// and [tag_name_len: 1 byte][tag_name: N bytes][record] for unions.
261// No intermediate StructValue/UnionValue types are needed — blobs are
262// constructed from registers and extracted directly into registers.
263
264#[derive(Debug, Clone)]
265#[cfg_attr(clt_turso_feature = "serde", derive(serde::Serialize, serde::Deserialize))]
266pub enum Value {
267    Null,
268    Numeric(Numeric),
269    Text(Text),
270    Blob(std::vec::Vec<u8>),
271}
272
273#[derive(Clone, Copy)]
274pub enum ValueRef<'a> {
275    Null,
276    Numeric(Numeric),
277    Text(TextRef<'a>),
278    Blob(&'a [u8]),
279}
280
281impl Debug for ValueRef<'_> {
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        match self {
284            ValueRef::Null => write!(f, "Null"),
285            ValueRef::Numeric(Numeric::Integer(i)) => f.debug_tuple("Integer").field(i).finish(),
286            ValueRef::Numeric(Numeric::Float(float)) => {
287                let fval: f64 = (*float).into();
288                f.debug_tuple("Float").field(&fval).finish()
289            }
290            ValueRef::Text(text_ref) => {
291                // truncate string to at most 256 chars
292                let text = text_ref.as_str();
293                let max_len = text.len().min(256);
294                f.debug_struct("Text")
295                    .field("data", &&text[0..max_len])
296                    // Indicates to the developer debugging that the data is truncated for printing
297                    .field("truncated", &(text.len() > max_len))
298                    .finish()
299            }
300            ValueRef::Blob(blob) => {
301                // truncate blob_slice to at most 32 bytes
302                let max_len = blob.len().min(32);
303                f.debug_struct("Blob")
304                    .field("data", &&blob[0..max_len])
305                    // Indicates to the developer debugging that the data is truncated for printing
306                    .field("truncated", &(blob.len() > max_len))
307                    .finish()
308            }
309        }
310    }
311}
312
313pub trait AsValueRef {
314    fn as_value_ref<'a>(&'a self) -> ValueRef<'a>;
315}
316
317impl<'b> AsValueRef for ValueRef<'b> {
318    #[inline]
319    fn as_value_ref<'a>(&'a self) -> ValueRef<'a> {
320        *self
321    }
322}
323
324impl AsValueRef for Value {
325    #[inline]
326    fn as_value_ref<'a>(&'a self) -> ValueRef<'a> {
327        self.as_ref()
328    }
329}
330
331impl AsValueRef for &mut Value {
332    #[inline]
333    fn as_value_ref<'a>(&'a self) -> ValueRef<'a> {
334        self.as_ref()
335    }
336}
337
338impl<V1, V2> AsValueRef for Either<V1, V2>
339where
340    V1: AsValueRef,
341    V2: AsValueRef,
342{
343    #[inline]
344    fn as_value_ref<'a>(&'a self) -> ValueRef<'a> {
345        match self {
346            Either::Left(left) => left.as_value_ref(),
347            Either::Right(right) => right.as_value_ref(),
348        }
349    }
350}
351
352impl<V: AsValueRef> AsValueRef for &V {
353    fn as_value_ref<'a>(&'a self) -> ValueRef<'a> {
354        (*self).as_value_ref()
355    }
356}
357
358impl Value {
359    pub const fn from_f64(f: f64) -> Self {
360        match NonNan::new(f) {
361            Some(nn) => Self::Numeric(Numeric::Float(nn)),
362            None => Self::Null,
363        }
364    }
365
366    pub const fn from_i64(i: i64) -> Self {
367        Self::Numeric(Numeric::Integer(i))
368    }
369
370    pub fn as_ref<'a>(&'a self) -> ValueRef<'a> {
371        match self {
372            Value::Null => ValueRef::Null,
373            Value::Numeric(n) => ValueRef::Numeric(*n),
374            Value::Text(v) => ValueRef::Text(TextRef {
375                value: &v.value,
376                subtype: v.subtype,
377            }),
378            Value::Blob(v) => ValueRef::Blob(v.as_slice()),
379        }
380    }
381
382    // A helper function that makes building a text Value easier.
383    pub fn build_text(text: impl Into<Cow<'static, str>>) -> Self {
384        Self::Text(Text::new(text))
385    }
386
387    pub fn to_blob(&self) -> Option<&[u8]> {
388        match self {
389            Self::Blob(blob) => Some(blob),
390            _ => None,
391        }
392    }
393
394    pub fn from_blob(data: std::vec::Vec<u8>) -> Self {
395        Value::Blob(data)
396    }
397
398    pub fn to_text(&self) -> Option<&str> {
399        match self {
400            Value::Text(t) => Some(t.as_str()),
401            _ => None,
402        }
403    }
404
405    pub const fn as_blob(&self) -> &std::vec::Vec<u8> {
406        match self {
407            Value::Blob(b) => b,
408            _ => panic!("as_blob must be called only for Value::Blob"),
409        }
410    }
411
412    pub const fn as_blob_mut(&mut self) -> &mut std::vec::Vec<u8> {
413        match self {
414            Value::Blob(b) => b,
415            _ => panic!("as_blob must be called only for Value::Blob"),
416        }
417    }
418    pub fn as_float(&self) -> f64 {
419        match self {
420            Value::Numeric(Numeric::Float(f)) => f64::from(*f),
421            Value::Numeric(Numeric::Integer(i)) => *i as f64,
422            _ => panic!("as_float must be called only for Value::Numeric"),
423        }
424    }
425
426    pub fn to_float_or_zero(&self) -> f64 {
427        match self {
428            Value::Numeric(Numeric::Float(f)) => f64::from(*f),
429            Value::Numeric(Numeric::Integer(i)) => *i as f64,
430            _ => 0.0,
431        }
432    }
433
434    pub const fn as_int(&self) -> Option<i64> {
435        match self {
436            Value::Numeric(Numeric::Integer(i)) => Some(*i),
437            _ => None,
438        }
439    }
440
441    pub const fn as_uint(&self) -> u64 {
442        match self {
443            Value::Numeric(Numeric::Integer(i)) => (*i).cast_unsigned(),
444            _ => 0,
445        }
446    }
447
448    pub fn from_text(text: impl Into<Cow<'static, str>>) -> Self {
449        Value::Text(Text::new(text))
450    }
451
452    pub const fn value_type(&self) -> ValueType {
453        match self {
454            Value::Null => ValueType::Null,
455            Value::Numeric(Numeric::Integer(_)) => ValueType::Integer,
456            Value::Numeric(Numeric::Float(_)) => ValueType::Float,
457            Value::Text(_) => ValueType::Text,
458            Value::Blob(_) => ValueType::Blob,
459        }
460    }
461    pub fn serialize_serial(&self, out: &mut std::vec::Vec<u8>) {
462        match self {
463            Value::Null => {}
464            Value::Numeric(Numeric::Integer(i)) => {
465                let serial_type = SerialType::from(self);
466                match serial_type.kind() {
467                    SerialTypeKind::I8 => out.extend_from_slice(&(*i as i8).to_be_bytes()),
468                    SerialTypeKind::I16 => out.extend_from_slice(&(*i as i16).to_be_bytes()),
469                    SerialTypeKind::I24 => out.extend_from_slice(&(*i as i32).to_be_bytes()[1..]), // remove most significant byte
470                    SerialTypeKind::I32 => out.extend_from_slice(&(*i as i32).to_be_bytes()),
471                    SerialTypeKind::I48 => out.extend_from_slice(&i.to_be_bytes()[2..]), // remove 2 most significant bytes
472                    SerialTypeKind::I64 => out.extend_from_slice(&i.to_be_bytes()),
473                    _ => unreachable!(),
474                }
475            }
476            Value::Numeric(Numeric::Float(f)) => {
477                let fval: f64 = (*f).into();
478                out.extend_from_slice(&fval.to_be_bytes());
479            }
480            Value::Text(t) => out.extend_from_slice(t.value.as_bytes()),
481            Value::Blob(b) => out.extend_from_slice(b),
482        };
483    }
484
485    /// Cast Value to String, if Value is NULL returns None
486    pub fn cast_text(&self) -> Option<String> {
487        Some(match self {
488            Value::Null => return None,
489            v => v.to_string(),
490        })
491    }
492}
493
494#[derive(Debug, Clone, PartialEq)]
495pub struct ExternalAggState {
496    pub context: usize,
497    pub state: *mut AggCtx,
498    pub argc: usize,
499    pub step_fn: StepFunction,
500    pub finalize_fn: FinalizeFunction,
501    pub aggregate_destructor: Option<ContextDestructor>,
502    pub value_destructor: Option<ValueDestructor>,
503}
504
505/// Please use Display trait for all limbo output so we have single origin of truth
506/// When you need value as string:
507/// ---GOOD---
508/// format!("{}", value);
509/// ---BAD---
510/// match value {
511///   Value::Numeric(Numeric::Integer(i)) => i.to_string(),
512///   Value::Numeric(Numeric::Float(f)) => f64::from(*f).to_string(),
513///   ....
514/// }
515impl Display for Value {
516    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
517        match self {
518            Self::Null => write!(f, ""),
519            Self::Numeric(Numeric::Integer(i)) => write!(f, "{i}"),
520            Self::Numeric(Numeric::Float(fl)) => f.write_str(&format_float(f64::from(*fl))),
521            Self::Text(s) => write!(f, "{}", s.as_str()),
522            Self::Blob(b) => write!(f, "{}", String::from_utf8_lossy(b)),
523        }
524    }
525}
526
527impl Value {
528    pub fn to_ffi(&self) -> ExtValue {
529        match self {
530            Self::Null => ExtValue::null(),
531            Self::Numeric(Numeric::Integer(i)) => ExtValue::from_integer(*i),
532            Self::Numeric(Numeric::Float(fl)) => ExtValue::from_float(f64::from(*fl)),
533            Self::Text(text) => ExtValue::from_text(text.as_str().to_string()),
534            Self::Blob(blob) => ExtValue::from_blob(blob.to_vec()),
535        }
536    }
537
538    pub(crate) fn from_ffi_ref(v: &ExtValue) -> Result<Self> {
539        match v.value_type() {
540            ExtValueType::Null => Ok(Value::Null),
541            ExtValueType::Integer => {
542                let Some(int) = v.to_integer() else {
543                    return Ok(Value::Null);
544                };
545                Ok(Value::from_i64(int))
546            }
547            ExtValueType::Float => {
548                let Some(float) = v.to_float() else {
549                    return Ok(Value::Null);
550                };
551                Ok(Value::from_f64(float))
552            }
553            ExtValueType::Text => {
554                let Some(text) = v.to_text() else {
555                    return Ok(Value::Null);
556                };
557                #[cfg(clt_turso_feature = "json")]
558                if v.is_json() {
559                    return Ok(Value::Text(Text::json(text.to_string())));
560                }
561                Ok(Value::build_text(text.to_string()))
562            }
563            ExtValueType::Blob => {
564                let Some(blob) = v.to_blob() else {
565                    return Ok(Value::Null);
566                };
567                Ok(Value::Blob(blob))
568            }
569            ExtValueType::Error => {
570                let Some(err) = v.to_error_details() else {
571                    return Ok(Value::Null);
572                };
573                match err {
574                    (_, Some(msg)) => Err(LimboError::ExtensionError(msg)),
575                    (code, None) => Err(LimboError::ExtensionError(code.to_string())),
576                }
577            }
578        }
579    }
580
581    pub fn from_ffi(v: ExtValue) -> Result<Self> {
582        let res = Self::from_ffi_ref(&v);
583        unsafe { v.__free_internal_type() };
584        res
585    }
586}
587
588/// Convert a `Value` into the implementors type.
589pub trait FromValue: Sealed {
590    fn from_sql(val: Value) -> Result<Self>
591    where
592        Self: Sized;
593}
594
595impl FromValue for Value {
596    fn from_sql(val: Value) -> Result<Self> {
597        Ok(val)
598    }
599}
600impl Sealed for crate::Value {}
601
602macro_rules! impl_int_from_value {
603    ($ty:ty, $cast:expr) => {
604        impl FromValue for $ty {
605            fn from_sql(val: Value) -> Result<Self> {
606                match val {
607                    Value::Null => Err(LimboError::NullValue),
608                    Value::Numeric(Numeric::Integer(i)) => Ok($cast(i)),
609                    _ => Err(LimboError::InvalidColumnType),
610                }
611            }
612        }
613
614        impl Sealed for $ty {}
615    };
616}
617
618impl_int_from_value!(i32, |i| i as i32);
619impl_int_from_value!(u32, |i| i as u32);
620impl_int_from_value!(i64, |i| i);
621impl_int_from_value!(u64, |i| i as u64);
622
623impl FromValue for f64 {
624    fn from_sql(val: Value) -> Result<Self> {
625        match val {
626            Value::Null => Err(LimboError::NullValue),
627            Value::Numeric(Numeric::Float(f)) => Ok(f64::from(f)),
628            _ => Err(LimboError::InvalidColumnType),
629        }
630    }
631}
632impl Sealed for f64 {}
633
634impl FromValue for std::vec::Vec<u8> {
635    fn from_sql(val: Value) -> Result<Self> {
636        match val {
637            Value::Null => Err(LimboError::NullValue),
638            Value::Blob(blob) => Ok(blob),
639            _ => Err(LimboError::InvalidColumnType),
640        }
641    }
642}
643impl Sealed for std::vec::Vec<u8> {}
644
645impl<const N: usize> FromValue for [u8; N] {
646    fn from_sql(val: Value) -> Result<Self> {
647        match val {
648            Value::Null => Err(LimboError::NullValue),
649            Value::Blob(blob) => blob.try_into().map_err(|_| LimboError::InvalidBlobSize(N)),
650            _ => Err(LimboError::InvalidColumnType),
651        }
652    }
653}
654impl<const N: usize> Sealed for [u8; N] {}
655
656impl FromValue for String {
657    fn from_sql(val: Value) -> Result<Self> {
658        match val {
659            Value::Null => Err(LimboError::NullValue),
660            Value::Text(s) => Ok(s.to_string()),
661            _ => Err(LimboError::InvalidColumnType),
662        }
663    }
664}
665impl Sealed for String {}
666
667impl FromValue for bool {
668    fn from_sql(val: Value) -> Result<Self> {
669        match val {
670            Value::Null => Err(LimboError::NullValue),
671            Value::Numeric(Numeric::Integer(i)) => match i {
672                0 => Ok(false),
673                1 => Ok(true),
674                _ => Err(LimboError::InvalidColumnType),
675            },
676            _ => Err(LimboError::InvalidColumnType),
677        }
678    }
679}
680impl Sealed for bool {}
681
682impl<T> FromValue for Option<T>
683where
684    T: FromValue,
685{
686    fn from_sql(val: Value) -> Result<Self> {
687        match val {
688            Value::Null => Ok(None),
689            _ => T::from_sql(val).map(Some),
690        }
691    }
692}
693impl<T> Sealed for Option<T> {}
694
695mod sealed {
696    pub trait Sealed {}
697}
698#[allow(unused_imports)] //used in doc comments
699use crate::vdbe::insn::Insn;
700use sealed::Sealed;
701
702#[derive(Debug, Clone, PartialEq)]
703pub struct SumAggState {
704    pub r_err: f64,   // Error term for Kahan-Babushka-Neumaier summation
705    pub approx: bool, // True if any non-integer value was input to the sum
706    pub ovrfl: bool,  // Integer overflow seen
707}
708impl Default for SumAggState {
709    fn default() -> Self {
710        Self {
711            r_err: 0.0,
712            approx: false,
713            ovrfl: false,
714        }
715    }
716}
717
718/// Aggregate context for accumulating values during GROUP BY.
719/// Built-in aggregates use a flat payload representation for efficiency and
720/// to share code between register-based and hash-based aggregation (future enhancement).
721#[derive(Debug, Clone, PartialEq)]
722pub enum AggContext {
723    /// Built-in aggregates store state as a flat Vec<Value> payload.
724    /// The layout depends on the aggregate function (see init_agg_payload).
725    Builtin(Vec<Value>),
726    /// External (extension) aggregates need FFI state that can't be serialized.
727    External(ExternalAggState),
728}
729
730impl AggContext {
731    pub fn compute_external(&self) -> Result<Value> {
732        if let Self::External(ext_state) = self {
733            let mut final_value =
734                unsafe { (ext_state.finalize_fn)(ext_state.context, ext_state.state) };
735            let value = Value::from_ffi_ref(&final_value);
736            if let Some(value_destructor) = ext_state.value_destructor {
737                unsafe { value_destructor(&mut final_value) };
738            } else {
739                unsafe { final_value.__free_internal_type() };
740            }
741            if let Some(aggregate_destructor) = ext_state.aggregate_destructor {
742                unsafe { aggregate_destructor(ext_state.state as usize) };
743            }
744            value
745        } else {
746            panic!("AggContext::compute_external() expected External, found {self:?}");
747        }
748    }
749
750    /// Get a mutable reference to the builtin payload as a slice
751    pub fn payload_mut(&mut self) -> &mut [Value] {
752        match self {
753            Self::Builtin(payload) => payload,
754            Self::External(_) => panic!("payload_mut() called on External aggregate"),
755        }
756    }
757
758    /// Get a mutable reference to the builtin payload Vec (for aggregates that
759    /// grow the payload, e.g. array_agg).
760    pub fn payload_vec_mut(&mut self) -> &mut Vec<Value> {
761        match self {
762            Self::Builtin(payload) => payload,
763            Self::External(_) => panic!("payload_vec_mut() called on External aggregate"),
764        }
765    }
766
767    /// Get an immutable reference to the builtin payload
768    pub fn payload(&self) -> &[Value] {
769        match self {
770            Self::Builtin(payload) => payload,
771            Self::External(_) => panic!("payload() called on External aggregate"),
772        }
773    }
774}
775
776impl PartialEq<Value> for Value {
777    fn eq(&self, other: &Value) -> bool {
778        let (left, right) = (self.as_value_ref(), other.as_value_ref());
779        left.eq(&right)
780    }
781}
782
783impl PartialOrd<Value> for Value {
784    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
785        Some(self.cmp(other))
786    }
787}
788
789impl PartialOrd<AggContext> for AggContext {
790    fn partial_cmp(&self, other: &AggContext) -> Option<std::cmp::Ordering> {
791        match (self, other) {
792            (Self::Builtin(a), Self::Builtin(b)) => {
793                // Compare by first element (the accumulator) if present
794                match (a.first(), b.first()) {
795                    (Some(a), Some(b)) => a.partial_cmp(b),
796                    _ => None,
797                }
798            }
799            _ => None,
800        }
801    }
802}
803
804impl Eq for Value {}
805
806impl Ord for Value {
807    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
808        let (left, right) = (self.as_value_ref(), other.as_value_ref());
809        left.cmp(&right)
810    }
811}
812
813impl std::ops::Add<Value> for Value {
814    type Output = Value;
815
816    fn add(mut self, rhs: Self) -> Self::Output {
817        self += rhs;
818        self
819    }
820}
821
822impl std::ops::Add<f64> for Value {
823    type Output = Value;
824
825    fn add(mut self, rhs: f64) -> Self::Output {
826        self += rhs;
827        self
828    }
829}
830
831impl std::ops::Add<i64> for Value {
832    type Output = Value;
833
834    fn add(mut self, rhs: i64) -> Self::Output {
835        self += rhs;
836        self
837    }
838}
839
840impl std::ops::AddAssign for Value {
841    fn add_assign(mut self: &mut Self, rhs: Self) {
842        match (&mut self, &rhs) {
843            (Self::Numeric(_), Self::Numeric(_)) => {
844                let sum = (|| {
845                    let lhs_num = Numeric::from_value(&self)?;
846                    let rhs_num = Numeric::from_value(&rhs)?;
847                    lhs_num.checked_add(rhs_num)
848                })();
849                *self = sum.into();
850            }
851            (Self::Text(string_left), Self::Text(string_right)) => {
852                string_left.value.to_mut().push_str(&string_right.value);
853                string_left.subtype = TextSubtype::Text;
854            }
855            (Self::Text(string_left), Self::Numeric(Numeric::Integer(int_right))) => {
856                let string_right = int_right.to_string();
857                string_left.value.to_mut().push_str(&string_right);
858                string_left.subtype = TextSubtype::Text;
859            }
860            (Self::Numeric(Numeric::Integer(int_left)), Self::Text(string_right)) => {
861                let string_left = int_left.to_string();
862                *self = Self::build_text(string_left + string_right.as_str());
863            }
864            (Self::Text(string_left), Self::Numeric(Numeric::Float(_))) => {
865                let string_right = rhs.to_string();
866                string_left.value.to_mut().push_str(&string_right);
867                string_left.subtype = TextSubtype::Text;
868            }
869            (Self::Numeric(Numeric::Float(_)), Self::Text(string_right)) => {
870                let string_left = self.to_string();
871                *self = Self::build_text(string_left + string_right.as_str());
872            }
873            (_, Self::Null) => {}
874            (Self::Null, _) => *self = rhs,
875            _ => *self = Self::from_f64(0.0),
876        }
877    }
878}
879
880impl std::ops::AddAssign<i64> for Value {
881    fn add_assign(&mut self, rhs: i64) {
882        let sum = (|| {
883            let lhs_num = Numeric::from_value(&self)?;
884            let rhs_num = Numeric::Integer(rhs);
885            lhs_num.checked_add(rhs_num)
886        })();
887        *self = sum.into();
888    }
889}
890
891impl std::ops::AddAssign<f64> for Value {
892    fn add_assign(&mut self, rhs: f64) {
893        let sum = (|| {
894            let lhs_num = Numeric::from_value(&self)?;
895            let rhs_num = NonNan::new(rhs).map(Numeric::Float)?;
896            lhs_num.checked_add(rhs_num)
897        })();
898
899        *self = sum.into();
900    }
901}
902
903impl std::ops::Div<Value> for Value {
904    type Output = Value;
905
906    fn div(self, rhs: Value) -> Self::Output {
907        let div = (|| {
908            let lhs_num = Numeric::from_value(self)?;
909            let rhs_num = Numeric::from_value(rhs)?;
910            lhs_num.checked_div(rhs_num)
911        })();
912        div.into()
913    }
914}
915
916impl std::ops::DivAssign<Value> for Value {
917    fn div_assign(&mut self, rhs: Value) {
918        *self = self.clone() / rhs;
919    }
920}
921
922impl From<ValueRef<'_>> for Value {
923    fn from(value: ValueRef<'_>) -> Self {
924        value.to_owned()
925    }
926}
927
928impl TryFrom<ValueRef<'_>> for i64 {
929    type Error = LimboError;
930
931    fn try_from(value: ValueRef<'_>) -> Result<Self, Self::Error> {
932        match value {
933            ValueRef::Numeric(Numeric::Integer(i)) => Ok(i),
934            _ => Err(LimboError::ConversionError("Expected integer value".into())),
935        }
936    }
937}
938
939impl TryFrom<ValueRef<'_>> for String {
940    type Error = LimboError;
941
942    #[inline]
943    fn try_from(value: ValueRef<'_>) -> Result<Self, Self::Error> {
944        Ok(<&str>::try_from(value)?.to_string())
945    }
946}
947
948impl<'a> TryFrom<ValueRef<'a>> for &'a str {
949    type Error = LimboError;
950
951    #[inline]
952    fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
953        match value {
954            ValueRef::Text(s) => Ok(s.as_str()),
955            _ => Err(LimboError::ConversionError("Expected text value".into())),
956        }
957    }
958}
959
960mod immutable_record {
961    use super::*;
962
963    /// This struct serves the purpose of not allocating multiple vectors of bytes if not needed.
964    /// A value in a record that has already been serialized can stay serialized and what this struct offsers
965    /// is easy acces to each value which point to the payload.
966    /// The name might be contradictory as it is immutable in the sense that you cannot modify the values without modifying the payload.
967    pub struct ImmutableRecord {
968        // We have to be super careful with this buffer since we make values point to the payload we need to take care reallocations
969        // happen in a controlled manner. If we realocate with values that should be correct, they will now point to undefined data.
970        // We don't use pin here because it would make it imposible to reuse the buffer if we need to push a new record in the same struct.
971        //
972        // payload is the std::vec::Vec<u8> but in order to use Register which holds ImmutableRecord as a Value - we store std::vec::Vec<u8> as Value::Blob
973        payload: Value,
974    }
975
976    // SAFETY: all ImmutableRecord instances are intended to be used in a single thread
977    // by a single connection.
978    unsafe impl Send for ImmutableRecord {}
979    unsafe impl Sync for ImmutableRecord {}
980
981    impl Clone for ImmutableRecord {
982        fn clone(&self) -> Self {
983            Self {
984                payload: self.payload.clone(),
985            }
986        }
987    }
988
989    impl PartialEq for ImmutableRecord {
990        fn eq(&self, other: &Self) -> bool {
991            self.payload == other.payload // Only compare payload, ignore cursor state
992        }
993    }
994
995    impl Eq for ImmutableRecord {}
996
997    impl PartialOrd for ImmutableRecord {
998        fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
999            Some(self.cmp(other))
1000        }
1001    }
1002
1003    impl Ord for ImmutableRecord {
1004        fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1005            self.payload.cmp(&other.payload) // Only compare payload, ignore cursor state
1006        }
1007    }
1008
1009    impl std::fmt::Debug for ImmutableRecord {
1010        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1011            match &self.payload {
1012                Value::Blob(bytes) => {
1013                    let preview = if bytes.len() > 20 {
1014                        format!("{:?} ... ({} bytes total)", &bytes[..20], bytes.len())
1015                    } else {
1016                        format!("{bytes:?}")
1017                    };
1018                    write!(f, "ImmutableRecord {{ payload: {preview} }}")
1019                }
1020                Value::Text(s) => {
1021                    let string = s.as_str();
1022                    let preview = if string.len() > 20 {
1023                        format!("{:?} ... ({} chars total)", &string[..20], string.len())
1024                    } else {
1025                        format!("{string:?}")
1026                    };
1027                    write!(f, "ImmutableRecord {{ payload: {preview} }}")
1028                }
1029                other => write!(f, "ImmutableRecord {{ payload: {other:?} }}"),
1030            }
1031        }
1032    }
1033
1034    #[derive(Clone, Copy)]
1035    pub struct ImmutableRecordRef<'a> {
1036        payload: &'a [u8],
1037    }
1038
1039    impl std::fmt::Debug for ImmutableRecordRef<'_> {
1040        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1041            let bytes = self.payload;
1042            let preview = if bytes.len() > 20 {
1043                format!("{:?} ... ({} bytes total)", &bytes[..20], bytes.len())
1044            } else {
1045                format!("{bytes:?}")
1046            };
1047            write!(f, "ImmutableRecordRef {{ payload: {preview} }}")
1048        }
1049    }
1050
1051    struct AppendWriter<'a> {
1052        buf: &'a mut std::vec::Vec<u8>,
1053        pos: usize,
1054        buf_capacity_start: usize,
1055        buf_ptr_start: *const u8,
1056    }
1057
1058    impl<'a> AppendWriter<'a> {
1059        fn new(buf: &'a mut std::vec::Vec<u8>, pos: usize) -> Self {
1060            let buf_ptr_start = buf.as_ptr();
1061            let buf_capacity_start = buf.capacity();
1062            Self {
1063                buf,
1064                pos,
1065                buf_capacity_start,
1066                buf_ptr_start,
1067            }
1068        }
1069
1070        #[inline]
1071        fn extend_from_slice(&mut self, slice: &[u8]) {
1072            self.buf[self.pos..self.pos + slice.len()].copy_from_slice(slice);
1073            self.pos += slice.len();
1074        }
1075
1076        fn assert_finish_capacity(&self) {
1077            // let's make sure we didn't reallocate anywhere else
1078            assert_eq!(self.buf_capacity_start, self.buf.capacity());
1079            assert_eq!(self.buf_ptr_start, self.buf.as_ptr());
1080        }
1081    }
1082
1083    #[inline(always)]
1084    fn iter(payload: &[u8]) -> Result<ValueIterator<'_>, LimboError> {
1085        ValueIterator::new(payload)
1086    }
1087
1088    fn values(payload: &[u8]) -> Result<Vec<ValueRef<'_>>> {
1089        let iter = iter(payload)?;
1090        let values = iter.try_collect::<Result<_>>()??;
1091        Ok(values)
1092    }
1093
1094    fn values_range(payload: &[u8], range: std::ops::Range<usize>) -> Result<Vec<ValueRef<'_>>> {
1095        let mut iter = iter(payload)?;
1096        let mut values = Vec::try_with_capacity_ext(range.end - range.start)?;
1097        if let Some(value) = iter.nth(range.start) {
1098            values.push(value?);
1099        } else {
1100            return Ok(values);
1101        }
1102        for _ in range.start + 1..range.end {
1103            if let Some(value) = iter.next() {
1104                values.push(value?);
1105            } else {
1106                break;
1107            }
1108        }
1109        Ok(values)
1110    }
1111
1112    fn two_values(
1113        payload: &[u8],
1114        idx1: usize,
1115        idx2: usize,
1116    ) -> Result<(ValueRef<'_>, ValueRef<'_>)> {
1117        let mut iter = iter(payload)?;
1118        let val1 = iter.nth(idx1);
1119        let val2 = iter.nth(idx2 - idx1 - 1);
1120        match (val1, val2) {
1121            (Some(v1), Some(v2)) => Ok((v1?, v2?)),
1122            _ => Err(LimboError::InternalError("index out of bound".to_string())),
1123        }
1124    }
1125
1126    fn three_values(
1127        payload: &[u8],
1128        idx1: usize,
1129        idx2: usize,
1130        idx3: usize,
1131    ) -> Result<(ValueRef<'_>, ValueRef<'_>, ValueRef<'_>)> {
1132        let mut iter = iter(payload)?;
1133        let val1 = iter.nth(idx1);
1134        let val2 = iter.nth(idx2 - idx1 - 1);
1135        let val3 = iter.nth(idx3 - idx2 - 1);
1136        match (val1, val2, val3) {
1137            (Some(v1), Some(v2), Some(v3)) => Ok((v1?, v2?, v3?)),
1138            _ => Err(LimboError::InternalError("index out of bound".to_string())),
1139        }
1140    }
1141
1142    fn four_values(
1143        payload: &[u8],
1144        idx1: usize,
1145        idx2: usize,
1146        idx3: usize,
1147        idx4: usize,
1148    ) -> Result<(ValueRef<'_>, ValueRef<'_>, ValueRef<'_>, ValueRef<'_>)> {
1149        let mut iter = iter(payload)?;
1150        let val1 = iter.nth(idx1);
1151        let val2 = iter.nth(idx2 - idx1 - 1);
1152        let val3 = iter.nth(idx3 - idx2 - 1);
1153        let val4 = iter.nth(idx4 - idx3 - 1);
1154        match (val1, val2, val3, val4) {
1155            (Some(v1), Some(v2), Some(v3), Some(v4)) => Ok((v1?, v2?, v3?, v4?)),
1156            _ => Err(LimboError::InternalError("index out of bound".to_string())),
1157        }
1158    }
1159
1160    fn values_owned(payload: &[u8]) -> Result<Vec<Value>> {
1161        let iter = iter(payload).expect("Failed to create payload iterator");
1162        let values = iter
1163            .map(|v| Ok::<_, LimboError>(v?.to_owned()))
1164            .try_collect::<Result<_>>()??;
1165        Ok(values)
1166    }
1167
1168    fn values_owned_range(payload: &[u8], range: std::ops::Range<usize>) -> Result<Vec<Value>> {
1169        let mut iter = iter(payload).expect("Failed to create payload iterator");
1170        let mut values = Vec::try_with_capacity_ext(range.end - range.start)?;
1171        if let Some(value) = iter.nth(range.start) {
1172            values.push(value?.to_owned());
1173        } else {
1174            return Ok(values);
1175        }
1176        for _ in range.start + 1..range.end {
1177            if let Some(value) = iter.next() {
1178                values.push(value?.to_owned());
1179            } else {
1180                break;
1181            }
1182        }
1183        Ok(values)
1184    }
1185
1186    fn contains_null(payload: &[u8]) -> Result<bool> {
1187        let (header_size, header_varint_len) = read_varint(payload)?;
1188        let header_size = header_size as usize;
1189
1190        if header_size > payload.len() || header_varint_len > payload.len() {
1191            return Err(LimboError::Corrupt(
1192                "Payload too small for indicated header size".into(),
1193            ));
1194        }
1195
1196        let mut header = &payload[header_varint_len..header_size];
1197
1198        while !header.is_empty() {
1199            let (serial_type, bytes_read) = read_varint(header)?;
1200            if serial_type == 0 {
1201                return Ok(true);
1202            }
1203            header = &header[bytes_read..];
1204        }
1205
1206        Ok(false)
1207    }
1208
1209    fn last_value(payload: &[u8]) -> Option<Result<ValueRef<'_>>> {
1210        if unlikely(payload.is_empty()) {
1211            return Some(Err(LimboError::InternalError(
1212                "Record is invalidated".into(),
1213            )));
1214        }
1215        let iter = match iter(payload) {
1216            Ok(it) => it,
1217            Err(e) => return Some(Err(e)),
1218        };
1219        iter.last()
1220    }
1221
1222    fn first_value(payload: &[u8]) -> Result<ValueRef<'_>> {
1223        if unlikely(payload.is_empty()) {
1224            return Err(LimboError::InternalError("Record is invalidated".into()));
1225        }
1226        match iter(payload)?.next() {
1227            Some(v) => v,
1228            None => Err(LimboError::InternalError("Record has no columns".into())),
1229        }
1230    }
1231
1232    fn value(payload: &[u8], idx: usize) -> Result<ValueRef<'_>> {
1233        if unlikely(payload.is_empty()) {
1234            return Err(LimboError::InternalError("Record is invalidated".into()));
1235        }
1236        let mut iter = iter(payload)?;
1237        iter.nth(idx)
1238            .transpose()?
1239            .ok_or_else(|| LimboError::InternalError("Index out of bounds".into()))
1240    }
1241
1242    fn value_opt(payload: &[u8], idx: usize) -> Option<ValueRef<'_>> {
1243        let mut iter = match iter(payload) {
1244            Ok(it) => it,
1245            Err(_) => {
1246                mark_unlikely();
1247                return None;
1248            }
1249        };
1250        match iter.nth(idx) {
1251            Some(Ok(v)) => Some(v),
1252            _ => {
1253                mark_unlikely();
1254                None
1255            }
1256        }
1257    }
1258
1259    fn column_count(payload: &[u8]) -> usize {
1260        iter(payload).map(|it| it.count()).unwrap_or_default()
1261    }
1262
1263    impl ImmutableRecord {
1264        // Don't use this in performance critical paths, prefer using `iter()` instead
1265        pub fn get_values(&self) -> Result<Vec<ValueRef<'_>>> {
1266            values(self.get_payload())
1267        }
1268
1269        // Don't use this in performance critical paths, prefer using `iter()` instead
1270        pub fn get_values_range(&self, range: std::ops::Range<usize>) -> Result<Vec<ValueRef<'_>>> {
1271            values_range(self.get_payload(), range)
1272        }
1273
1274        // Idx values must be sorted ascending
1275        pub fn get_two_values(
1276            &self,
1277            idx1: usize,
1278            idx2: usize,
1279        ) -> Result<(ValueRef<'_>, ValueRef<'_>)> {
1280            two_values(self.get_payload(), idx1, idx2)
1281        }
1282
1283        // Idx values must be sorted ascending
1284        pub fn get_three_values(
1285            &self,
1286            idx1: usize,
1287            idx2: usize,
1288            idx3: usize,
1289        ) -> Result<(ValueRef<'_>, ValueRef<'_>, ValueRef<'_>)> {
1290            three_values(self.get_payload(), idx1, idx2, idx3)
1291        }
1292
1293        // Idx values must be sorted ascending
1294        pub fn get_four_values(
1295            &self,
1296            idx1: usize,
1297            idx2: usize,
1298            idx3: usize,
1299            idx4: usize,
1300        ) -> Result<(ValueRef<'_>, ValueRef<'_>, ValueRef<'_>, ValueRef<'_>)> {
1301            four_values(self.get_payload(), idx1, idx2, idx3, idx4)
1302        }
1303
1304        // Don't use this in performance critical paths, prefer using `iter()` instead
1305        pub fn get_values_owned(&self) -> Result<Vec<Value>> {
1306            values_owned(self.get_payload())
1307        }
1308
1309        // Don't use this in performance critical paths, prefer using `iter()` instead
1310        pub fn get_values_owned_range(&self, range: std::ops::Range<usize>) -> Result<Vec<Value>> {
1311            values_owned_range(self.get_payload(), range)
1312        }
1313
1314        #[inline(always)]
1315        pub fn iter(&self) -> Result<ValueIterator<'_>, LimboError> {
1316            iter(self.get_payload())
1317        }
1318
1319        #[inline]
1320        /// Returns true if the record contains any NULL values.
1321        /// This is an optimization that only examines the header (serial types)
1322        /// without deserializing the data section.
1323        pub fn contains_null(&self) -> Result<bool> {
1324            contains_null(self.get_payload())
1325        }
1326
1327        #[inline]
1328        pub fn last_value(&self) -> Option<Result<ValueRef<'_>>> {
1329            last_value(self.get_payload())
1330        }
1331
1332        #[inline]
1333        pub fn first_value(&self) -> Result<ValueRef<'_>> {
1334            first_value(self.get_payload())
1335        }
1336
1337        #[inline]
1338        pub fn get_value(&self, idx: usize) -> Result<ValueRef<'_>> {
1339            value(self.get_payload(), idx)
1340        }
1341
1342        #[inline]
1343        pub fn get_value_opt(&self, idx: usize) -> Option<ValueRef<'_>> {
1344            value_opt(self.get_payload(), idx)
1345        }
1346
1347        pub fn column_count(&self) -> usize {
1348            column_count(self.get_payload())
1349        }
1350    }
1351
1352    impl<'a> ImmutableRecordRef<'a> {
1353        #[inline(always)]
1354        pub fn iter(&self) -> Result<ValueIterator<'a>, LimboError> {
1355            iter(self.payload)
1356        }
1357
1358        pub fn get_values(&self) -> Result<Vec<ValueRef<'a>>> {
1359            values(self.payload)
1360        }
1361
1362        pub fn get_two_values(
1363            &self,
1364            idx1: usize,
1365            idx2: usize,
1366        ) -> Result<(ValueRef<'a>, ValueRef<'a>)> {
1367            two_values(self.payload, idx1, idx2)
1368        }
1369
1370        pub fn get_three_values(
1371            &self,
1372            idx1: usize,
1373            idx2: usize,
1374            idx3: usize,
1375        ) -> Result<(ValueRef<'_>, ValueRef<'_>, ValueRef<'_>)> {
1376            three_values(self.get_payload(), idx1, idx2, idx3)
1377        }
1378
1379        pub fn get_values_owned(&self) -> Result<Vec<Value>> {
1380            values_owned(self.payload)
1381        }
1382
1383        #[inline]
1384        pub fn get_value_opt(&self, idx: usize) -> Option<ValueRef<'a>> {
1385            value_opt(self.payload, idx)
1386        }
1387
1388        pub fn column_count(&self) -> usize {
1389            column_count(self.payload)
1390        }
1391    }
1392
1393    impl ImmutableRecord {
1394        pub fn new(payload_capacity: usize) -> Result<Self> {
1395            let mut payload = std::vec::Vec::new();
1396            payload.try_reserve_exact(payload_capacity)?;
1397            Ok(Self {
1398                payload: Value::Blob(payload),
1399            })
1400        }
1401
1402        pub const fn from_bin_record(payload: std::vec::Vec<u8>) -> Self {
1403            Self {
1404                payload: Value::Blob(payload),
1405            }
1406        }
1407
1408        pub fn as_record_ref(&self) -> ImmutableRecordRef<'_> {
1409            ImmutableRecordRef::from_bin_record(self.get_payload())
1410        }
1411
1412        pub fn from_registers<'a, I: Iterator<Item = &'a Register> + Clone>(
1413            // we need to accept both &[Register] and &[&Register] values - that's why non-trivial signature
1414            //
1415            // std::slice::Iter under the hood just stores pointer and length of slice and also implements a Clone which just copy those meta-values
1416            // (without copying the data itself)
1417            registers: impl IntoIterator<Item = &'a Register, IntoIter = I>,
1418            len: usize,
1419        ) -> Result<Self> {
1420            Self::from_values(registers.into_iter().map(|x| x.get_value()), len)
1421        }
1422
1423        pub fn from_values<'a>(
1424            values: impl IntoIterator<Item = impl AsValueRef + 'a> + Clone,
1425            len: usize,
1426        ) -> Result<Self> {
1427            let mut serials = Vec::try_with_capacity_ext(len)?;
1428            let mut size_header = 0;
1429            let mut size_values = 0;
1430
1431            let mut serial_type_buf = [0; 9];
1432            // write serial types
1433            for value in values.clone() {
1434                let serial_type = SerialType::from(value.as_value_ref());
1435                let n = write_varint(&mut serial_type_buf[0..], serial_type.into());
1436                serials.push((serial_type_buf, n));
1437
1438                let value_size = serial_type.size();
1439
1440                size_header += n;
1441                size_values += value_size;
1442            }
1443
1444            let header_size = Record::calc_header_size(size_header);
1445
1446            // 1. write header size
1447            let mut buf = std::vec::Vec::new();
1448            buf.try_reserve_exact(header_size + size_values)?;
1449            assert_eq!(buf.capacity(), header_size + size_values);
1450            let n = write_varint(&mut serial_type_buf, header_size as u64);
1451
1452            buf.resize(buf.capacity(), 0);
1453            let mut writer = AppendWriter::new(&mut buf, 0);
1454            writer.extend_from_slice(&serial_type_buf[..n]);
1455
1456            // 2. Write serial
1457            for (value, n) in serials {
1458                writer.extend_from_slice(&value[..n]);
1459            }
1460
1461            // write content
1462            for value in values {
1463                let value = value.as_value_ref();
1464                match value {
1465                    ValueRef::Null => {}
1466                    ValueRef::Numeric(Numeric::Integer(i)) => {
1467                        let serial_type = SerialType::from(value);
1468                        match serial_type.kind() {
1469                            SerialTypeKind::ConstInt0 | SerialTypeKind::ConstInt1 => {}
1470                            SerialTypeKind::I8 => {
1471                                writer.extend_from_slice(&(i as i8).to_be_bytes())
1472                            }
1473                            SerialTypeKind::I16 => {
1474                                writer.extend_from_slice(&(i as i16).to_be_bytes())
1475                            }
1476                            SerialTypeKind::I24 => {
1477                                writer.extend_from_slice(&(i as i32).to_be_bytes()[1..])
1478                            } // remove most significant byte
1479                            SerialTypeKind::I32 => {
1480                                writer.extend_from_slice(&(i as i32).to_be_bytes())
1481                            }
1482                            SerialTypeKind::I48 => writer.extend_from_slice(&i.to_be_bytes()[2..]), // remove 2 most significant bytes
1483                            SerialTypeKind::I64 => writer.extend_from_slice(&i.to_be_bytes()),
1484                            other => panic!("Serial type is not an integer: {other:?}"),
1485                        }
1486                    }
1487                    ValueRef::Numeric(Numeric::Float(f)) => {
1488                        let fval: f64 = f.into();
1489                        writer.extend_from_slice(&fval.to_be_bytes());
1490                    }
1491                    ValueRef::Text(t) => {
1492                        writer.extend_from_slice(t.value.as_bytes());
1493                    }
1494                    ValueRef::Blob(b) => {
1495                        writer.extend_from_slice(b);
1496                    }
1497                };
1498            }
1499
1500            writer.assert_finish_capacity();
1501            Ok(Self {
1502                payload: Value::Blob(buf),
1503            })
1504        }
1505
1506        #[inline]
1507        pub fn into_payload(self) -> std::vec::Vec<u8> {
1508            match self.payload {
1509                Value::Blob(b) => b,
1510                _ => panic!("payload must be a blob"),
1511            }
1512        }
1513
1514        #[inline]
1515        pub const fn as_blob(&self) -> &std::vec::Vec<u8> {
1516            match &self.payload {
1517                Value::Blob(b) => b,
1518                _ => panic!("payload must be a blob"),
1519            }
1520        }
1521
1522        #[inline]
1523        pub const fn as_blob_mut(&mut self) -> &mut std::vec::Vec<u8> {
1524            match &mut self.payload {
1525                Value::Blob(b) => b,
1526                _ => panic!("payload must be a blob"),
1527            }
1528        }
1529
1530        #[inline]
1531        pub const fn as_blob_value(&self) -> &Value {
1532            &self.payload
1533        }
1534
1535        #[inline]
1536        pub fn start_serialization(&mut self, payload: &[u8]) -> Result<()> {
1537            let blob = self.as_blob_mut();
1538            blob.try_reserve(payload.len())?;
1539            blob.extend_from_slice(payload);
1540            Ok(())
1541        }
1542
1543        #[inline]
1544        pub fn invalidate(&mut self) {
1545            self.as_blob_mut().clear();
1546        }
1547
1548        #[inline]
1549        pub const fn is_invalidated(&self) -> bool {
1550            self.as_blob().is_empty()
1551        }
1552
1553        #[inline]
1554        pub fn get_payload(&self) -> &[u8] {
1555            self.as_blob()
1556        }
1557    }
1558
1559    impl<'a> ImmutableRecordRef<'a> {
1560        pub const fn from_bin_record(payload: &'a [u8]) -> Self {
1561            Self { payload }
1562        }
1563
1564        #[inline]
1565        pub const fn get_payload(&self) -> &'a [u8] {
1566            self.payload
1567        }
1568
1569        #[inline]
1570        pub const fn is_invalidated(&self) -> bool {
1571            self.payload.is_empty()
1572        }
1573    }
1574}
1575
1576pub use immutable_record::{ImmutableRecord, ImmutableRecordRef};
1577
1578#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1579pub struct Record {
1580    values: Vec<Value>,
1581}
1582
1583impl Record {
1584    // pub fn get<'a, T: FromValue<'a> + 'a>(&'a self, idx: usize) -> Result<T> {
1585    //     let value = &self.values[idx];
1586    //     T::from_value(value)
1587    // }
1588
1589    pub fn count(&self) -> usize {
1590        self.values.len()
1591    }
1592
1593    pub fn last_value(&self) -> Option<&Value> {
1594        self.values.last()
1595    }
1596
1597    pub fn get_values(&self) -> &Vec<Value> {
1598        &self.values
1599    }
1600
1601    pub fn get_value(&self, idx: usize) -> &Value {
1602        &self.values[idx]
1603    }
1604
1605    pub fn len(&self) -> usize {
1606        self.values.len()
1607    }
1608
1609    pub fn is_empty(&self) -> bool {
1610        self.values.is_empty()
1611    }
1612}
1613
1614/// A zero-allocation iterator over SQLite record payload data.
1615///
1616/// This iterator provides efficient, lazy parsing of SQLite records without
1617/// any heap allocation. It processes record data on-the-fly, returning `ValueRef`
1618/// instances that borrow directly from the underlying payload.
1619///
1620/// # Memory Layout
1621///
1622/// SQLite records follow this binary format:
1623/// ```text
1624/// [header_size: varint][serial_type1: varint][serial_type2: varint]...
1625/// [data1][data2][data3]...
1626/// ```
1627///
1628/// - **header_size**: Total bytes in the header section (including this varint)
1629/// - **serial_typeN**: Encodes the type and size of column N's data
1630/// - **dataN**: The actual data for column N (length determined by serial_typeN)
1631pub struct ValueIterator<'a> {
1632    /// Reference to header section up to data offset
1633    header_section: Cell<&'a [u8]>,
1634    /// Reference to data section only
1635    data_section: Cell<&'a [u8]>,
1636}
1637
1638impl<'a> ValueIterator<'a> {
1639    /// Creates a new payload iterator from a raw payload slice.
1640    ///
1641    /// # Arguments
1642    ///
1643    /// * `payload` - The serialized SQLite record payload
1644    ///
1645    /// # Returns
1646    ///
1647    /// Returns `Ok(Self)` if the header can be parsed, or an error if the
1648    /// payload is malformed.
1649    #[inline(always)]
1650    pub fn new(payload: &'a [u8]) -> Result<Self> {
1651        let (header_size, header_varint_len) = read_varint(payload)?;
1652        let header_size = header_size as usize;
1653
1654        if header_size > payload.len()
1655            || header_varint_len > payload.len()
1656            || header_varint_len > header_size
1657        {
1658            return Err(LimboError::Corrupt(
1659                "Payload too small for indicated header size".into(),
1660            ));
1661        }
1662
1663        Ok(Self {
1664            header_section: Cell::new(&payload[header_varint_len..header_size]),
1665            data_section: Cell::new(&payload[header_size..]),
1666        })
1667    }
1668
1669    /// Returns `true` if the payload is empty or the record has no columns.
1670    pub const fn is_empty(&self) -> bool {
1671        self.header_section.get().is_empty()
1672    }
1673
1674    /// Returns a reference to the current header section.
1675    #[inline(always)]
1676    pub const fn header_section_ref(&self) -> &'a [u8] {
1677        self.header_section.get()
1678    }
1679
1680    /// Returns a reference to the current data section.
1681    #[inline(always)]
1682    pub const fn data_section_ref(&self) -> &'a [u8] {
1683        self.data_section.get()
1684    }
1685
1686    /// Sets the header section to a new slice.
1687    #[inline(always)]
1688    pub fn set_header_section(&self, header: &'a [u8]) {
1689        self.header_section.set(header);
1690    }
1691
1692    /// Sets the data section to a new slice.
1693    #[inline(always)]
1694    pub fn set_data_section(&self, data: &'a [u8]) {
1695        self.data_section.set(data);
1696    }
1697}
1698
1699impl<'a> Iterator for ValueIterator<'a> {
1700    type Item = Result<ValueRef<'a>, LimboError>;
1701
1702    #[inline(always)]
1703    fn count(self) -> usize
1704    where
1705        Self: Sized,
1706    {
1707        let mut count = 0;
1708        let mut header = self.header_section.get();
1709        while !header.is_empty() {
1710            match read_varint(header) {
1711                Ok((_, bytes_read)) => {
1712                    count += 1;
1713                    header = &header[bytes_read..];
1714                }
1715                Err(_) => break,
1716            }
1717        }
1718        count
1719    }
1720
1721    #[inline(always)]
1722    fn size_hint(&self) -> (usize, Option<usize>) {
1723        let mut count = 0;
1724        let mut header = self.header_section.get();
1725        while !header.is_empty() {
1726            match read_varint(header) {
1727                Ok((_, bytes_read)) => {
1728                    count += 1;
1729                    header = &header[bytes_read..];
1730                }
1731                Err(_) => break,
1732            }
1733        }
1734        (count, Some(count))
1735    }
1736
1737    fn fold<B, F>(self, init: B, mut f: F) -> B
1738    where
1739        F: FnMut(B, Self::Item) -> B,
1740    {
1741        let mut acc = init;
1742        for item in self {
1743            acc = f(acc, item);
1744        }
1745        acc
1746    }
1747
1748    /// Returns the nth element of the iterator.
1749    #[inline(always)]
1750    fn nth(&mut self, n: usize) -> Option<Self::Item> {
1751        let mut header = self.header_section.get();
1752        let mut data = self.data_section.get();
1753
1754        let mut data_sum = 0;
1755        for _ in 0..n {
1756            if unlikely(header.is_empty()) {
1757                return None;
1758            }
1759
1760            let (serial_type, bytes_read) = match read_varint(header) {
1761                Ok(v) => v,
1762                Err(e) => {
1763                    mark_unlikely();
1764                    return Some(Err(e));
1765                }
1766            };
1767            header = &header[bytes_read..];
1768
1769            data_sum += match get_serial_type_size(serial_type) {
1770                Ok(size) => size,
1771                Err(e) => {
1772                    mark_unlikely();
1773                    return Some(Err(e));
1774                }
1775            };
1776        }
1777
1778        if unlikely(data_sum > data.len()) {
1779            return Some(Err(LimboError::Corrupt(
1780                "Data section too small for indicated serial type size".into(),
1781            )));
1782        }
1783        data = &data[data_sum..];
1784
1785        // Update iterator state
1786        self.header_section.set(header);
1787        self.data_section.set(data);
1788
1789        // Return the nth value
1790        self.next()
1791    }
1792
1793    #[inline(always)]
1794    fn next(&mut self) -> Option<Self::Item> {
1795        let header = self.header_section.get();
1796        if unlikely(header.is_empty()) {
1797            return None;
1798        }
1799
1800        // Read next serial type
1801        let (serial_type, bytes_read) = match read_varint(header) {
1802            Ok(v) => v,
1803            Err(e) => {
1804                mark_unlikely();
1805                return Some(Err(e));
1806            }
1807        };
1808
1809        // Update header section to remove the consumed serial type
1810        self.header_section.set(&header[bytes_read..]);
1811
1812        let data_section = self.data_section.get();
1813
1814        match crate::storage::sqlite3_ondisk::read_value_serial_type(data_section, serial_type) {
1815            Ok((value, n)) => {
1816                self.data_section.set(&data_section[n..]);
1817                Some(Ok(value))
1818            }
1819            Err(e) => {
1820                mark_unlikely();
1821                Some(Err(e))
1822            }
1823        }
1824    }
1825}
1826
1827// Optimization: indicate that once the iterator is exhausted, it will always return None.
1828impl<'a> FusedIterator for ValueIterator<'a> {}
1829
1830impl<'a> Clone for ValueIterator<'a> {
1831    fn clone(&self) -> Self {
1832        Self {
1833            header_section: Cell::new(self.header_section.get()),
1834            data_section: Cell::new(self.data_section.get()),
1835        }
1836    }
1837}
1838
1839impl<'a> ValueRef<'a> {
1840    pub fn from_f64(f: f64) -> Self {
1841        match NonNan::new(f) {
1842            Some(nn) => Self::Numeric(Numeric::Float(nn)),
1843            None => Self::Null,
1844        }
1845    }
1846
1847    pub fn from_i64(i: i64) -> Self {
1848        Self::Numeric(Numeric::Integer(i))
1849    }
1850
1851    pub fn to_ffi(&self) -> ExtValue {
1852        match self {
1853            Self::Null => ExtValue::null(),
1854            Self::Numeric(Numeric::Integer(i)) => ExtValue::from_integer(*i),
1855            Self::Numeric(Numeric::Float(fl)) => ExtValue::from_float(f64::from(*fl)),
1856            Self::Text(text) => ExtValue::from_text(text.as_str().to_string()),
1857            Self::Blob(blob) => ExtValue::from_blob(blob.to_vec()),
1858        }
1859    }
1860
1861    pub fn to_blob(&self) -> Option<&'a [u8]> {
1862        match self {
1863            Self::Blob(blob) => Some(*blob),
1864            _ => None,
1865        }
1866    }
1867
1868    pub fn to_text(&self) -> Option<&'a str> {
1869        match self {
1870            Self::Text(t) => Some(t.as_str()),
1871            _ => None,
1872        }
1873    }
1874
1875    pub fn as_blob(&self) -> &'a [u8] {
1876        match self {
1877            Self::Blob(b) => b,
1878            _ => panic!("as_blob must be called only for Value::Blob"),
1879        }
1880    }
1881
1882    pub fn as_float(&self) -> f64 {
1883        match self {
1884            Self::Numeric(Numeric::Float(f)) => f64::from(*f),
1885            Self::Numeric(Numeric::Integer(i)) => *i as f64,
1886            _ => panic!("as_float must be called only for ValueRef::Numeric"),
1887        }
1888    }
1889
1890    pub const fn as_int(&self) -> Option<i64> {
1891        match self {
1892            Self::Numeric(Numeric::Integer(i)) => Some(*i),
1893            _ => None,
1894        }
1895    }
1896
1897    pub const fn as_uint(&self) -> u64 {
1898        match self {
1899            Self::Numeric(Numeric::Integer(i)) => (*i).cast_unsigned(),
1900            _ => 0,
1901        }
1902    }
1903
1904    #[inline]
1905    pub fn to_owned(&self) -> Value {
1906        match self {
1907            ValueRef::Null => Value::Null,
1908            ValueRef::Numeric(n) => Value::from(*n),
1909            ValueRef::Text(text) => Value::Text(Text {
1910                value: text.value.to_string().into(),
1911                subtype: text.subtype,
1912            }),
1913            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
1914        }
1915    }
1916
1917    pub fn value_type(&self) -> ValueType {
1918        match self {
1919            Self::Null => ValueType::Null,
1920            Self::Numeric(Numeric::Integer(_)) => ValueType::Integer,
1921            Self::Numeric(Numeric::Float(_)) => ValueType::Float,
1922            Self::Text(_) => ValueType::Text,
1923            Self::Blob(_) => ValueType::Blob,
1924        }
1925    }
1926}
1927
1928impl Display for ValueRef<'_> {
1929    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1930        match self {
1931            Self::Null => write!(f, "NULL"),
1932            Self::Numeric(Numeric::Integer(i)) => write!(f, "{i}"),
1933            Self::Numeric(Numeric::Float(fl)) => {
1934                let fval: f64 = (*fl).into();
1935                write!(f, "{fval:?}")
1936            }
1937            Self::Text(s) => write!(f, "{}", s.as_str()),
1938            Self::Blob(b) => write!(f, "{}", String::from_utf8_lossy(b)),
1939        }
1940    }
1941}
1942
1943impl<'a> PartialEq<ValueRef<'a>> for ValueRef<'a> {
1944    fn eq(&self, other: &ValueRef<'a>) -> bool {
1945        match (self, other) {
1946            (Self::Null, Self::Null) => true,
1947            (Self::Numeric(a), Self::Numeric(b)) => a == b,
1948            (Self::Text(text_left), Self::Text(text_right)) => {
1949                text_left.value.as_bytes() == text_right.value.as_bytes()
1950            }
1951            (Self::Blob(blob_left), Self::Blob(blob_right)) => blob_left.eq(blob_right),
1952            _ => false,
1953        }
1954    }
1955}
1956
1957impl<'a> PartialEq<Value> for ValueRef<'a> {
1958    fn eq(&self, other: &Value) -> bool {
1959        let other = other.as_value_ref();
1960        self.eq(&other)
1961    }
1962}
1963
1964impl<'a> Eq for ValueRef<'a> {}
1965
1966impl<'a> PartialOrd<ValueRef<'a>> for ValueRef<'a> {
1967    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1968        Some(self.cmp(other))
1969    }
1970}
1971
1972impl<'a> Ord for ValueRef<'a> {
1973    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1974        match (self, other) {
1975            (Self::Null, Self::Null) => std::cmp::Ordering::Equal,
1976            (Self::Null, _) => std::cmp::Ordering::Less,
1977            (_, Self::Null) => std::cmp::Ordering::Greater,
1978
1979            (Self::Numeric(a), Self::Numeric(b)) => a.cmp(b),
1980
1981            // Numeric < Text < Blob
1982            (Self::Numeric(_), _) => std::cmp::Ordering::Less,
1983            (_, Self::Numeric(_)) => std::cmp::Ordering::Greater,
1984
1985            (Self::Text(text_left), Self::Text(text_right)) => {
1986                text_left.value.as_bytes().cmp(text_right.value.as_bytes())
1987            }
1988            (Self::Text(_), Self::Blob(_)) => std::cmp::Ordering::Less,
1989            (Self::Blob(_), Self::Text(_)) => std::cmp::Ordering::Greater,
1990
1991            (Self::Blob(blob_left), Self::Blob(blob_right)) => blob_left.cmp(blob_right),
1992        }
1993    }
1994}
1995
1996#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1997pub struct KeyInfo {
1998    pub sort_order: SortOrder,
1999    pub collation: CollationSeq,
2000    pub nulls_order: Option<turso_parser::ast::NullsOrder>,
2001}
2002
2003#[cfg(not(nightly))]
2004pub type IndexKeyInfo = Vec<KeyInfo>;
2005#[cfg(nightly)]
2006pub type IndexKeyInfo = Vec<KeyInfo, DynAllocator>;
2007
2008#[derive(Debug, Clone, PartialEq, Eq)]
2009/// Metadata about an index, used for handling and comparing index keys.
2010///
2011/// This struct provides information about the sorting order of columns,
2012/// whether the index includes a row ID, and the total number of columns
2013/// in the index.
2014pub struct IndexInfo {
2015    /// Specifies the sorting order (ascending or descending) for each column in the index.
2016    pub key_info: IndexKeyInfo,
2017    /// Indicates whether the index includes a row ID column.
2018    pub has_rowid: bool,
2019    /// The total number of columns in the index, including the row ID column if present.
2020    pub num_cols: usize,
2021    /// Indicates whether index rows should be unique.
2022    pub is_unique: bool,
2023}
2024
2025impl Default for IndexInfo {
2026    fn default() -> Self {
2027        Self {
2028            key_info: Self::key_info_in(TursoAllocator),
2029            has_rowid: true,
2030            num_cols: 1,
2031            is_unique: false,
2032        }
2033    }
2034}
2035
2036impl IndexInfo {
2037    pub fn key_info_in<A: ConcurrentAllocator>(alloc: A) -> IndexKeyInfo {
2038        <IndexKeyInfo as TursoVecInExt<KeyInfo, DynAllocator>>::new_in(DynAllocator::new(alloc))
2039    }
2040
2041    #[cfg(not(nightly))]
2042    pub fn key_info_from_iter_in<A, I>(
2043        key_info: I,
2044        _alloc: A,
2045    ) -> Result<IndexKeyInfo, TryReserveError>
2046    where
2047        A: ConcurrentAllocator,
2048        I: IntoIterator<Item = KeyInfo>,
2049    {
2050        key_info.into_iter().try_collect()
2051    }
2052
2053    #[cfg(nightly)]
2054    pub fn key_info_from_iter_in<A, I>(
2055        key_info: I,
2056        alloc: A,
2057    ) -> Result<IndexKeyInfo, TryReserveError>
2058    where
2059        A: ConcurrentAllocator,
2060        I: IntoIterator<Item = KeyInfo>,
2061    {
2062        key_info
2063            .into_iter()
2064            .try_collect_in(DynAllocator::new(alloc))
2065    }
2066
2067    pub fn new<I>(
2068        key_info: I,
2069        has_rowid: bool,
2070        num_cols: usize,
2071        is_unique: bool,
2072    ) -> Result<Self, TryReserveError>
2073    where
2074        I: IntoIterator<Item = KeyInfo>,
2075    {
2076        Self::new_in(key_info, has_rowid, num_cols, is_unique, TursoAllocator)
2077    }
2078
2079    pub fn new_in<A, I>(
2080        key_info: I,
2081        has_rowid: bool,
2082        num_cols: usize,
2083        is_unique: bool,
2084        alloc: A,
2085    ) -> Result<Self, TryReserveError>
2086    where
2087        A: ConcurrentAllocator,
2088        I: IntoIterator<Item = KeyInfo>,
2089    {
2090        Ok(Self {
2091            key_info: Self::key_info_from_iter_in(key_info, alloc)?,
2092            has_rowid,
2093            num_cols,
2094            is_unique,
2095        })
2096    }
2097
2098    pub fn new_from_index(index: &Index) -> Result<Self, TryReserveError> {
2099        Self::new_from_index_in(index, TursoAllocator)
2100    }
2101
2102    pub fn new_from_index_in<A: ConcurrentAllocator>(
2103        index: &Index,
2104        alloc: A,
2105    ) -> Result<Self, TryReserveError> {
2106        let key_info = index
2107            .columns
2108            .iter()
2109            .map(|c| KeyInfo {
2110                sort_order: c.order,
2111                collation: c.collation.unwrap_or_default(),
2112                nulls_order: None,
2113            })
2114            .chain(index.has_rowid.then_some(KeyInfo {
2115                sort_order: SortOrder::Asc,
2116                collation: CollationSeq::Binary,
2117                nulls_order: None,
2118            }));
2119        Self::new_in(
2120            key_info,
2121            index.has_rowid,
2122            index.columns.len() + (index.has_rowid as usize),
2123            index.unique,
2124            alloc,
2125        )
2126    }
2127}
2128
2129pub fn compare_immutable<V1, V2, E1, E2, I1, I2>(
2130    l: I1,
2131    r: I2,
2132    column_info: &[KeyInfo],
2133) -> std::cmp::Ordering
2134where
2135    V1: AsValueRef,
2136    V2: AsValueRef,
2137    E1: ExactSizeIterator<Item = V1>,
2138    E2: ExactSizeIterator<Item = V2>,
2139    I1: IntoIterator<IntoIter = E1, Item = E1::Item>,
2140    I2: IntoIterator<IntoIter = E2, Item = E2::Item>,
2141{
2142    let (l, r): (E1, E2) = (l.into_iter(), r.into_iter());
2143    assert!(
2144        l.len() >= column_info.len(),
2145        "{} < {}",
2146        l.len(),
2147        column_info.len()
2148    );
2149    assert!(
2150        r.len() >= column_info.len(),
2151        "{} < {}",
2152        r.len(),
2153        column_info.len()
2154    );
2155    let (l, r) = (l.take(column_info.len()), r.take(column_info.len()));
2156    for (i, (l, r)) in l.zip(r).enumerate() {
2157        let column_order = column_info[i].sort_order;
2158        let collation = column_info[i].collation;
2159        let cmp = compare_immutable_single(l, r, collation);
2160        if !cmp.is_eq() {
2161            return match column_order {
2162                SortOrder::Asc => cmp,
2163                SortOrder::Desc => cmp.reverse(),
2164            };
2165        }
2166    }
2167    std::cmp::Ordering::Equal
2168}
2169
2170pub fn compare_immutable_iter<V, E1, E2>(
2171    mut l: E1,
2172    mut r: E2,
2173    column_info: &[KeyInfo],
2174) -> Result<std::cmp::Ordering>
2175where
2176    V: AsValueRef,
2177    E1: Iterator<Item = Result<V>>,
2178    E2: Iterator<Item = Result<V>>,
2179{
2180    for col_info in column_info.iter() {
2181        let l = match l.next() {
2182            Some(v) => v,
2183            None => break,
2184        };
2185        let r = match r.next() {
2186            Some(v) => v,
2187            None => break,
2188        };
2189        let column_order = col_info.sort_order;
2190        let collation = col_info.collation;
2191        let cmp = compare_immutable_single(l?, r?, collation);
2192        if !cmp.is_eq() {
2193            return match column_order {
2194                SortOrder::Asc => Ok(cmp),
2195                SortOrder::Desc => Ok(cmp.reverse()),
2196            };
2197        }
2198    }
2199    Ok(std::cmp::Ordering::Equal)
2200}
2201
2202pub fn compare_immutable_single<V1, V2>(l: V1, r: V2, collation: CollationSeq) -> std::cmp::Ordering
2203where
2204    V1: AsValueRef,
2205    V2: AsValueRef,
2206{
2207    let l = l.as_value_ref();
2208    let r = r.as_value_ref();
2209    match (l, r) {
2210        (ValueRef::Text(left), ValueRef::Text(right)) => collation.compare_strings(&left, &right),
2211        _ => l.cmp(&r),
2212    }
2213}
2214
2215#[derive(Debug, Clone, Copy)]
2216pub enum RecordCompare {
2217    Int,
2218    String,
2219    Generic,
2220}
2221
2222impl RecordCompare {
2223    pub fn compare<V, E, I>(
2224        &self,
2225        serialized: &ImmutableRecord,
2226        unpacked: I,
2227        index_info: &IndexInfo,
2228        skip: usize,
2229        tie_breaker: std::cmp::Ordering,
2230    ) -> Result<std::cmp::Ordering>
2231    where
2232        V: AsValueRef,
2233        E: ExactSizeIterator<Item = V>,
2234        I: IntoIterator<IntoIter = E, Item = E::Item>,
2235    {
2236        let unpacked = unpacked.into_iter();
2237        match self {
2238            RecordCompare::Int => {
2239                compare_records_int(serialized, unpacked, index_info, tie_breaker)
2240            }
2241            RecordCompare::String => {
2242                compare_records_string(serialized, unpacked, index_info, tie_breaker)
2243            }
2244            RecordCompare::Generic => {
2245                compare_records_generic(serialized, unpacked, index_info, skip, tie_breaker)
2246            }
2247        }
2248    }
2249}
2250
2251pub fn find_compare<I, E, V>(unpacked: I, index_info: &IndexInfo) -> RecordCompare
2252where
2253    V: AsValueRef,
2254    E: ExactSizeIterator<Item = V>,
2255    I: IntoIterator<IntoIter = Peekable<E>, Item = V>,
2256{
2257    let mut unpacked = unpacked.into_iter();
2258    if unpacked.len() != 0 && index_info.num_cols <= 13 {
2259        let val = unpacked.peek().unwrap();
2260        match val.as_value_ref() {
2261            ValueRef::Numeric(Numeric::Integer(_)) => RecordCompare::Int,
2262            ValueRef::Text(_) if index_info.key_info[0].collation == CollationSeq::Binary => {
2263                RecordCompare::String
2264            }
2265            _ => RecordCompare::Generic,
2266        }
2267    } else {
2268        RecordCompare::Generic
2269    }
2270}
2271
2272pub fn get_tie_breaker_from_seek_op(seek_op: SeekOp) -> std::cmp::Ordering {
2273    match seek_op {
2274        // exact‐match “key == X” opcodes
2275        SeekOp::GE { eq_only: true } | SeekOp::LE { eq_only: true } => std::cmp::Ordering::Equal,
2276
2277        // forward search – want the *first* ≥ / > key
2278        SeekOp::GE { eq_only: false } => std::cmp::Ordering::Greater,
2279        SeekOp::GT => std::cmp::Ordering::Less,
2280
2281        // backward search – want the *last* ≤ / < key
2282        SeekOp::LE { eq_only: false } => std::cmp::Ordering::Less,
2283        SeekOp::LT => std::cmp::Ordering::Greater,
2284    }
2285}
2286
2287/// Optimized integer-first record comparison function.
2288///
2289/// This function is an optimized version of `compare_records_generic()` for the
2290/// common case where:
2291/// - (a) The first field of the unpacked record is an integer
2292/// - (b) The serialized record's first field is also an integer
2293/// - (c) The header size varint fits in a single byte and is ≤ 63 bytes
2294///
2295/// The 63-byte header limit prevents buffer overreads and ensures safe direct
2296/// memory access patterns. This optimization avoids generic parsing overhead
2297/// by directly extracting and comparing integer values using known layouts.
2298///
2299/// # Fast Path Conditions
2300///
2301/// The function uses the optimized path when ALL of these conditions are met:
2302/// - Payload is at least 2 bytes (header size + first serial type)
2303/// - First serial type indicates integer (`1-6`, `8`, or `9`)
2304/// - First unpacked field is a `ValueRef::Numeric(Numeric::Integer)`
2305///
2306/// If any condition fails, it falls back to `compare_records_generic()`.
2307///
2308/// # Arguments
2309///
2310/// * `serialized` - The left-hand side record in serialized format
2311/// * `unpacked` - The right-hand side record as an array of parsed values
2312/// * `index_info` - Contains sort order information for each field
2313/// * `collations` - Array of collation sequences (unused for integers)
2314/// * `tie_breaker` - Result to return when all compared fields are equal
2315///
2316/// /// # Comparison Logic
2317///
2318/// The function follows optimized integer comparison semantics:
2319///
2320/// 1. **Type validation**: Ensures both sides are integers, otherwise falls back
2321/// 2. **Direct extraction**: Reads integer value using specialized decoder
2322/// 3. **Native comparison**: Uses Rust's built-in `i64::cmp()` for speed
2323/// 4. **Sort order**: Applies ascending/descending order to comparison result
2324/// 5. **Remaining fields**: If first field is equal and more fields exist,
2325///    delegates to `compare_records_generic()` with `skip=1`
2326fn compare_records_int<V, I>(
2327    serialized: &ImmutableRecord,
2328    unpacked: I,
2329    index_info: &IndexInfo,
2330    tie_breaker: std::cmp::Ordering,
2331) -> Result<std::cmp::Ordering>
2332where
2333    V: AsValueRef,
2334    I: ExactSizeIterator<Item = V>,
2335{
2336    let payload = serialized.get_payload();
2337    if payload.len() < 2 {
2338        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2339    }
2340
2341    let (header_size, offset_1st_serialtype) = read_varint(payload)?;
2342    let header_size = header_size as usize;
2343
2344    if payload.len() < header_size {
2345        return Err(LimboError::Corrupt(format!(
2346            "Record payload too short: claimed header size {} but payload only {} bytes",
2347            header_size,
2348            payload.len()
2349        )));
2350    }
2351
2352    let (first_serial_type, _) = read_varint(&payload[offset_1st_serialtype..])?;
2353
2354    let serialtype_is_integer = matches!(first_serial_type, 1..=6 | 8 | 9);
2355    if !serialtype_is_integer {
2356        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2357    }
2358
2359    let data_start = header_size;
2360
2361    let lhs_int = read_integer(&payload[data_start..], first_serial_type as u8)?;
2362    let mut unpacked = unpacked.peekable();
2363    // Do not consume iterator here
2364    let ValueRef::Numeric(Numeric::Integer(rhs_int)) = unpacked.peek().unwrap().as_value_ref()
2365    else {
2366        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2367    };
2368    let comparison = match index_info.key_info[0].sort_order {
2369        SortOrder::Asc => lhs_int.cmp(&rhs_int),
2370        SortOrder::Desc => lhs_int.cmp(&rhs_int).reverse(),
2371    };
2372    match comparison {
2373        std::cmp::Ordering::Equal => {
2374            // First fields equal, compare remaining fields if any
2375            if unpacked.len() > 1 {
2376                return compare_records_generic(serialized, unpacked, index_info, 1, tie_breaker);
2377            }
2378            Ok(tie_breaker)
2379        }
2380        other => Ok(other),
2381    }
2382}
2383
2384/// This function is an optimized version of `compare_records_generic()` for the
2385/// common case where:
2386/// - (a) The first field of the unpacked record is a string
2387/// - (b) The serialized record's first field is also a string
2388/// - (c) The header size varint fits in a single byte (most records)
2389///
2390/// This optimization avoids the overhead of generic field parsing by directly
2391/// accessing the first string field using known offsets, then falling back to
2392/// the generic comparison for remaining fields if needed.
2393///
2394/// # Fast Path Conditions
2395///
2396/// The function uses the optimized path when ALL of these conditions are met:
2397/// - Payload is at least 2 bytes (header size + first serial type)
2398/// - Header size fits in single byte (`payload[0] < 0x80`)
2399/// - First serial type indicates string (`>= 13` and odd number)
2400/// - First unpacked field is a `RefValue::Text`
2401///
2402/// If any condition fails, it falls back to `compare_records_generic()`.
2403///
2404/// # Arguments
2405///
2406/// * `serialized` - The left-hand side record in serialized format
2407/// * `unpacked` - The right-hand side record as an array of parsed values
2408/// * `index_info` - Contains sort order information for each field
2409/// * `collations` - Array of collation sequences for string comparisons
2410/// * `tie_breaker` - Result to return when all compared fields are equal
2411///
2412/// # Comparison Logic
2413///
2414/// The function follows SQLite's string comparison semantics:
2415///
2416/// 1. **Type checking**: Ensures both sides are strings, otherwise falls back
2417/// 2. **String comparison**: Uses collation if provided, binary otherwise
2418/// 3. **Sort order**: Applies ascending/descending order to comparison result
2419/// 4. **Length comparison**: If strings are equal, compares lengths
2420/// 5. **Remaining fields**: If first field is equal and more fields exist,
2421///    delegates to `compare_records_generic()` with `skip=1`
2422fn compare_records_string<V, I>(
2423    serialized: &ImmutableRecord,
2424    unpacked: I,
2425    index_info: &IndexInfo,
2426    tie_breaker: std::cmp::Ordering,
2427) -> Result<std::cmp::Ordering>
2428where
2429    V: AsValueRef,
2430    I: ExactSizeIterator<Item = V>,
2431{
2432    let payload = serialized.get_payload();
2433    if payload.len() < 2 {
2434        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2435    }
2436
2437    let (header_size, offset_1st_serialtype) = read_varint(payload)?;
2438    let header_size = header_size as usize;
2439
2440    if payload.len() < header_size {
2441        return Err(LimboError::Corrupt(format!(
2442            "Record payload too short: claimed header size {} but payload only {} bytes",
2443            header_size,
2444            payload.len()
2445        )));
2446    }
2447
2448    let (first_serial_type, _) = read_varint(&payload[offset_1st_serialtype..])?;
2449
2450    let serialtype_is_string = first_serial_type >= 13 && (first_serial_type & 1) == 1;
2451    if !serialtype_is_string {
2452        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2453    }
2454
2455    let mut unpacked = unpacked.peekable();
2456
2457    let ValueRef::Text(rhs_text) = unpacked.peek().unwrap().as_value_ref() else {
2458        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2459    };
2460
2461    let string_len = (first_serial_type as usize - 13) / 2;
2462    let data_start = header_size;
2463
2464    turso_debug_assert!(data_start + string_len <= payload.len());
2465
2466    let serial_type = SerialType::try_from(first_serial_type)?;
2467    let (lhs_value, _) = read_value(&payload[data_start..], serial_type)?;
2468
2469    let ValueRef::Text(lhs_text) = lhs_value else {
2470        return compare_records_generic(serialized, unpacked, index_info, 0, tie_breaker);
2471    };
2472
2473    let collation = index_info.key_info[0].collation;
2474    let comparison = collation.compare_strings(&lhs_text, &rhs_text);
2475
2476    let final_comparison = match index_info.key_info[0].sort_order {
2477        SortOrder::Asc => comparison,
2478        SortOrder::Desc => comparison.reverse(),
2479    };
2480
2481    match final_comparison {
2482        std::cmp::Ordering::Equal => {
2483            let len_cmp = lhs_text.len().cmp(&rhs_text.len());
2484            if len_cmp != std::cmp::Ordering::Equal {
2485                let adjusted = match index_info.key_info[0].sort_order {
2486                    SortOrder::Asc => len_cmp,
2487                    SortOrder::Desc => len_cmp.reverse(),
2488                };
2489                return Ok(adjusted);
2490            }
2491
2492            if unpacked.len() > 1 {
2493                return compare_records_generic(serialized, unpacked, index_info, 1, tie_breaker);
2494            }
2495            Ok(tie_breaker)
2496        }
2497        other => Ok(other),
2498    }
2499}
2500
2501/// Compare two table rows or index records.
2502///
2503/// This function compares a serialized record (`serialized`) with an unpacked
2504/// record (`unpacked`) and returns a comparison result. It returns `Less`, `Equal`,
2505/// or `Greater` if the serialized record is less than, equal to, or greater than
2506/// the unpacked record.
2507///
2508/// The `serialized` record must be a blob created by the record serialization
2509/// process (equivalent to SQLite's OP_MakeRecord opcode). The `unpacked` record
2510/// must be a parsed key array of `RefValue` objects.
2511///
2512/// # Arguments
2513///
2514/// * `serialized` - The left-hand side record in serialized format
2515/// * `unpacked` - The right-hand side record as an array of parsed values
2516/// * `index_info` - Contains sort order information for each field
2517/// * `collations` - Array of collation sequences for string comparisons
2518/// * `skip` - Number of initial fields to skip (assumes caller verified equality)
2519/// * `tie_breaker` - Result to return when all compared fields are equal
2520///
2521/// # Skipping Fields
2522///
2523/// If `skip` is non-zero, it is assumed that the caller has already determined
2524/// that the first `skip` fields of the records are equal. This function will
2525/// begin comparing at field index `skip`, skipping over the header and data
2526/// portions of the already-verified fields.
2527///
2528/// # Field Count Differences
2529///
2530/// The serialized and unpacked records do not have to contain the same number
2531/// of fields. If all fields that appear in both records are equal, then
2532/// `tie_breaker` is returned.
2533pub fn compare_records_generic<V, I>(
2534    serialized: &ImmutableRecord,
2535    unpacked: I,
2536    index_info: &IndexInfo,
2537    skip: usize,
2538    tie_breaker: std::cmp::Ordering,
2539) -> Result<std::cmp::Ordering>
2540where
2541    V: AsValueRef,
2542    I: ExactSizeIterator<Item = V>,
2543{
2544    let payload = serialized.get_payload();
2545    if payload.is_empty() {
2546        return Ok(std::cmp::Ordering::Less);
2547    }
2548
2549    let (header_size, mut header_pos) = read_varint(payload)?;
2550    let header_end = header_size as usize;
2551    turso_debug_assert!(header_end <= payload.len());
2552
2553    let mut data_pos = header_size as usize;
2554
2555    // Skip over `skip` number of fields
2556    for _ in 0..skip {
2557        if header_pos >= header_end {
2558            break;
2559        }
2560
2561        let (serial_type_raw, bytes_read) = read_varint(&payload[header_pos..])?;
2562        header_pos += bytes_read;
2563
2564        let serial_type = SerialType::try_from(serial_type_raw)?;
2565        if !matches!(
2566            serial_type.kind(),
2567            SerialTypeKind::ConstInt0 | SerialTypeKind::ConstInt1 | SerialTypeKind::Null
2568        ) {
2569            data_pos += serial_type.size();
2570        }
2571    }
2572
2573    let mut field_idx = skip;
2574    let field_limit = unpacked.len().min(index_info.key_info.len());
2575
2576    // assumes that that the `unpacked' iterator was not skipped outside this function call`
2577    for rhs_value in unpacked.skip(skip) {
2578        let rhs_value = &rhs_value.as_value_ref();
2579        if field_idx >= field_limit || header_pos >= header_end {
2580            break;
2581        }
2582        let (serial_type_raw, bytes_read) = read_varint(&payload[header_pos..])?;
2583        header_pos += bytes_read;
2584
2585        let serial_type = SerialType::try_from(serial_type_raw)?;
2586
2587        let lhs_value = match serial_type.kind() {
2588            SerialTypeKind::ConstInt0 => ValueRef::Numeric(Numeric::Integer(0)),
2589            SerialTypeKind::ConstInt1 => ValueRef::Numeric(Numeric::Integer(1)),
2590            SerialTypeKind::Null => ValueRef::Null,
2591            _ => {
2592                let (value, field_size) = read_value(&payload[data_pos..], serial_type)?;
2593                data_pos += field_size;
2594                value
2595            }
2596        };
2597
2598        let comparison = match (&lhs_value, rhs_value) {
2599            (ValueRef::Text(lhs_text), ValueRef::Text(rhs_text)) => index_info.key_info[field_idx]
2600                .collation
2601                .compare_strings(lhs_text, rhs_text),
2602
2603            _ => lhs_value.cmp(rhs_value),
2604        };
2605
2606        let final_comparison = match index_info.key_info[field_idx].sort_order {
2607            SortOrder::Asc => comparison,
2608            SortOrder::Desc => comparison.reverse(),
2609        };
2610
2611        if final_comparison != std::cmp::Ordering::Equal {
2612            return Ok(final_comparison);
2613        }
2614
2615        field_idx += 1;
2616    }
2617
2618    Ok(tie_breaker)
2619}
2620
2621const I8_LOW: i64 = -128;
2622const I8_HIGH: i64 = 127;
2623const I16_LOW: i64 = -32768;
2624const I16_HIGH: i64 = 32767;
2625const I24_LOW: i64 = -8388608;
2626const I24_HIGH: i64 = 8388607;
2627const I32_LOW: i64 = -2147483648;
2628const I32_HIGH: i64 = 2147483647;
2629const I48_LOW: i64 = -140737488355328;
2630const I48_HIGH: i64 = 140737488355327;
2631
2632/// Sqlite Serial Types
2633/// https://www.sqlite.org/fileformat.html#record_format
2634#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
2635#[repr(transparent)]
2636pub struct SerialType(u64);
2637
2638#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
2639pub enum SerialTypeKind {
2640    Null,
2641    I8,
2642    I16,
2643    I24,
2644    I32,
2645    I48,
2646    I64,
2647    F64,
2648    ConstInt0,
2649    ConstInt1,
2650    Text,
2651    Blob,
2652}
2653
2654impl SerialType {
2655    #[inline(always)]
2656    pub fn u64_is_valid_serial_type(n: u64) -> bool {
2657        n != 10 && n != 11
2658    }
2659
2660    const NULL: Self = Self(0);
2661    const I8: Self = Self(1);
2662    const I16: Self = Self(2);
2663    const I24: Self = Self(3);
2664    const I32: Self = Self(4);
2665    const I48: Self = Self(5);
2666    const I64: Self = Self(6);
2667    const F64: Self = Self(7);
2668    const CONST_INT0: Self = Self(8);
2669    const CONST_INT1: Self = Self(9);
2670
2671    pub const fn null() -> Self {
2672        Self::NULL
2673    }
2674
2675    pub const fn i8() -> Self {
2676        Self::I8
2677    }
2678
2679    pub const fn i16() -> Self {
2680        Self::I16
2681    }
2682
2683    pub const fn i24() -> Self {
2684        Self::I24
2685    }
2686
2687    pub const fn i32() -> Self {
2688        Self::I32
2689    }
2690
2691    pub const fn i48() -> Self {
2692        Self::I48
2693    }
2694
2695    pub const fn i64() -> Self {
2696        Self::I64
2697    }
2698
2699    pub const fn f64() -> Self {
2700        Self::F64
2701    }
2702
2703    pub const fn const_int0() -> Self {
2704        Self::CONST_INT0
2705    }
2706
2707    pub const fn const_int1() -> Self {
2708        Self::CONST_INT1
2709    }
2710
2711    pub const fn blob(size: u64) -> Self {
2712        Self(12 + size * 2)
2713    }
2714
2715    pub const fn text(size: u64) -> Self {
2716        Self(13 + size * 2)
2717    }
2718
2719    #[inline(always)]
2720    pub const fn kind(&self) -> SerialTypeKind {
2721        match self.0 {
2722            0 => SerialTypeKind::Null,
2723            1 => SerialTypeKind::I8,
2724            2 => SerialTypeKind::I16,
2725            3 => SerialTypeKind::I24,
2726            4 => SerialTypeKind::I32,
2727            5 => SerialTypeKind::I48,
2728            6 => SerialTypeKind::I64,
2729            7 => SerialTypeKind::F64,
2730            8 => SerialTypeKind::ConstInt0,
2731            9 => SerialTypeKind::ConstInt1,
2732            n if n >= 12 => match n % 2 {
2733                0 => SerialTypeKind::Blob,
2734                1 => SerialTypeKind::Text,
2735                _ => {
2736                    mark_unlikely();
2737                    unreachable!();
2738                }
2739            },
2740            _ => {
2741                mark_unlikely();
2742                unreachable!();
2743            }
2744        }
2745    }
2746
2747    pub const fn size(&self) -> usize {
2748        match self.kind() {
2749            SerialTypeKind::Null => 0,
2750            SerialTypeKind::I8 => 1,
2751            SerialTypeKind::I16 => 2,
2752            SerialTypeKind::I24 => 3,
2753            SerialTypeKind::I32 => 4,
2754            SerialTypeKind::I48 => 6,
2755            SerialTypeKind::I64 => 8,
2756            SerialTypeKind::F64 => 8,
2757            SerialTypeKind::ConstInt0 => 0,
2758            SerialTypeKind::ConstInt1 => 0,
2759            SerialTypeKind::Text => (self.0 as usize - 13) / 2,
2760            SerialTypeKind::Blob => (self.0 as usize - 12) / 2,
2761        }
2762    }
2763}
2764
2765#[inline(always)]
2766pub fn get_serial_type_size(serial: u64) -> Result<usize> {
2767    match serial {
2768        0 | 8 | 9 => Ok(0),
2769        1 => Ok(1),
2770        2 => Ok(2),
2771        3 => Ok(3),
2772        4 => Ok(4),
2773        5 => Ok(6),
2774        6 | 7 => Ok(8),
2775        n if n >= 12 => match n % 2 {
2776            0 => Ok(((n - 12) / 2) as usize), // Blob
2777            1 => Ok(((n - 13) / 2) as usize), // Text
2778            _ => {
2779                mark_unlikely();
2780                unreachable!();
2781            }
2782        },
2783        _ => {
2784            mark_unlikely();
2785            Err(LimboError::Corrupt(format!(
2786                "Invalid serial type: {serial}"
2787            )))
2788        }
2789    }
2790}
2791
2792impl<T: AsValueRef> From<T> for SerialType {
2793    fn from(value: T) -> Self {
2794        let value = value.as_value_ref();
2795        match value {
2796            ValueRef::Null => SerialType::null(),
2797            ValueRef::Numeric(Numeric::Integer(i)) => match i {
2798                0 => SerialType::const_int0(),
2799                1 => SerialType::const_int1(),
2800                i if (I8_LOW..=I8_HIGH).contains(&i) => SerialType::i8(),
2801                i if (I16_LOW..=I16_HIGH).contains(&i) => SerialType::i16(),
2802                i if (I24_LOW..=I24_HIGH).contains(&i) => SerialType::i24(),
2803                i if (I32_LOW..=I32_HIGH).contains(&i) => SerialType::i32(),
2804                i if (I48_LOW..=I48_HIGH).contains(&i) => SerialType::i48(),
2805                _ => SerialType::i64(),
2806            },
2807            ValueRef::Numeric(Numeric::Float(_)) => SerialType::f64(),
2808            ValueRef::Text(t) => SerialType::text(t.value.len() as u64),
2809            ValueRef::Blob(b) => SerialType::blob(b.len() as u64),
2810        }
2811    }
2812}
2813
2814impl From<SerialType> for u64 {
2815    fn from(serial_type: SerialType) -> Self {
2816        serial_type.0
2817    }
2818}
2819
2820impl TryFrom<u64> for SerialType {
2821    type Error = LimboError;
2822
2823    #[inline(always)]
2824    fn try_from(uint: u64) -> Result<Self> {
2825        if unlikely(uint == 10 || uint == 11) {
2826            return Err(LimboError::Corrupt(format!("Invalid serial type: {uint}")));
2827        }
2828        Ok(SerialType(uint))
2829    }
2830}
2831
2832impl Record {
2833    pub fn new(values: Vec<Value>) -> Self {
2834        Self { values }
2835    }
2836
2837    /// Calculates the total size needed for a SQLite record header.
2838    ///
2839    /// The record header consists of:
2840    /// 1. A varint encoding the total header size (self-referentially, e.g. a 100 byte header literally has the number '100' in the header suffix)
2841    /// 2. A sequence of varints encoding the serial types
2842    ///
2843    /// For small headers (<=126 bytes), we only need 1 byte to encode the header size, because 127 fits in 7 bits (varint uses 7 bits for the value and 1 continuation bit)
2844    /// For larger headers, we need to account for the variable length of the header size varint.
2845    pub fn calc_header_size(sizeof_serial_types: usize) -> usize {
2846        if sizeof_serial_types < i8::MAX as usize {
2847            return sizeof_serial_types + 1;
2848        }
2849
2850        let mut header_size = sizeof_serial_types;
2851        // For larger headers, calculate how many bytes we need for the header size varint
2852        let mut temp_buf = [0u8; 9];
2853        let mut prev_header_size;
2854
2855        loop {
2856            prev_header_size = header_size;
2857            let varint_len = write_varint(&mut temp_buf, header_size as u64);
2858            header_size = sizeof_serial_types + varint_len;
2859
2860            if header_size == prev_header_size {
2861                break;
2862            }
2863        }
2864
2865        header_size
2866    }
2867
2868    pub fn serialize(&self, buf: &mut std::vec::Vec<u8>) {
2869        let initial_i = buf.len();
2870
2871        // write serial types
2872        for value in &self.values {
2873            let serial_type = SerialType::from(value);
2874            buf.resize(buf.len() + 9, 0); // Ensure space for varint (1-9 bytes in length)
2875            let len = buf.len();
2876            let n = write_varint(&mut buf[len - 9..], serial_type.into());
2877            buf.truncate(buf.len() - 9 + n); // Remove unused bytes
2878        }
2879
2880        let mut header_size = buf.len() - initial_i;
2881        // write content
2882        for value in &self.values {
2883            match value {
2884                Value::Null => {}
2885                Value::Numeric(Numeric::Integer(i)) => {
2886                    let serial_type = SerialType::from(value);
2887                    match serial_type.kind() {
2888                        SerialTypeKind::ConstInt0 | SerialTypeKind::ConstInt1 => {}
2889                        SerialTypeKind::I8 => buf.extend_from_slice(&(*i as i8).to_be_bytes()),
2890                        SerialTypeKind::I16 => buf.extend_from_slice(&(*i as i16).to_be_bytes()),
2891                        SerialTypeKind::I24 => {
2892                            buf.extend_from_slice(&(*i as i32).to_be_bytes()[1..])
2893                        } // remove most significant byte
2894                        SerialTypeKind::I32 => buf.extend_from_slice(&(*i as i32).to_be_bytes()),
2895                        SerialTypeKind::I48 => buf.extend_from_slice(&i.to_be_bytes()[2..]), // remove 2 most significant bytes
2896                        SerialTypeKind::I64 => buf.extend_from_slice(&i.to_be_bytes()),
2897                        _ => {
2898                            mark_unlikely();
2899                            unreachable!();
2900                        }
2901                    }
2902                }
2903                Value::Numeric(Numeric::Float(f)) => {
2904                    buf.extend_from_slice(&f64::from(*f).to_be_bytes())
2905                }
2906                Value::Text(t) => buf.extend_from_slice(t.value.as_bytes()),
2907                Value::Blob(b) => buf.extend_from_slice(b),
2908            };
2909        }
2910
2911        let mut header_bytes_buf = std::vec::Vec::new();
2912        header_size = Record::calc_header_size(header_size);
2913        header_bytes_buf.extend(std::iter::repeat_n(0, 9));
2914        let n = write_varint(header_bytes_buf.as_mut_slice(), header_size as u64);
2915        header_bytes_buf.truncate(n);
2916        buf.splice(initial_i..initial_i, header_bytes_buf.iter().cloned());
2917    }
2918}
2919
2920pub enum Cursor {
2921    BTree(Box<dyn CursorTrait>),
2922    IndexMethod(Box<dyn IndexMethodCursor>),
2923    Pseudo(Box<PseudoCursor>),
2924    Sorter(Box<Sorter>),
2925    Virtual(VirtualTableCursor),
2926    MaterializedView(Box<crate::incremental::cursor::MaterializedViewCursor>),
2927}
2928
2929impl Debug for Cursor {
2930    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2931        match self {
2932            Self::BTree(..) => f.debug_tuple("BTree").finish(),
2933            Self::IndexMethod(..) => f.debug_tuple("IndexMethod").finish(),
2934            Self::Pseudo(..) => f.debug_tuple("Pseudo").finish(),
2935            Self::Sorter(..) => f.debug_tuple("Sorter").finish(),
2936            Self::Virtual(..) => f.debug_tuple("Virtual").finish(),
2937            Self::MaterializedView(..) => f.debug_tuple("MaterializedView").finish(),
2938        }
2939    }
2940}
2941
2942impl Cursor {
2943    pub fn new_btree(cursor: Box<dyn CursorTrait>) -> Self {
2944        // Matches sqlite3BtreeCursor adding to BtShared.pCursor (btree.c:4699).
2945        cursor.register_with_pager();
2946        Self::BTree(cursor)
2947    }
2948
2949    pub fn new_pseudo(cursor: PseudoCursor) -> Self {
2950        Self::Pseudo(Box::new(cursor))
2951    }
2952
2953    pub fn new_sorter(cursor: Sorter) -> Self {
2954        Self::Sorter(Box::new(cursor))
2955    }
2956
2957    pub fn new_materialized_view(
2958        cursor: crate::incremental::cursor::MaterializedViewCursor,
2959    ) -> Self {
2960        Self::MaterializedView(Box::new(cursor))
2961    }
2962
2963    pub fn as_btree_mut(&mut self) -> &mut dyn CursorTrait {
2964        match self {
2965            Self::BTree(cursor) => cursor.as_mut(),
2966            _ => {
2967                mark_unlikely();
2968                panic!("Cursor is not a btree cursor");
2969            }
2970        }
2971    }
2972
2973    pub fn as_pseudo_mut(&mut self) -> &mut PseudoCursor {
2974        match self {
2975            Self::Pseudo(cursor) => cursor,
2976            _ => {
2977                mark_unlikely();
2978                panic!("Cursor is not a pseudo cursor");
2979            }
2980        }
2981    }
2982
2983    pub fn as_sorter_mut(&mut self) -> &mut Sorter {
2984        match self {
2985            Self::Sorter(cursor) => cursor,
2986            _ => {
2987                mark_unlikely();
2988                panic!("Cursor is not a sorter cursor")
2989            }
2990        }
2991    }
2992
2993    pub fn as_virtual_mut(&mut self) -> &mut VirtualTableCursor {
2994        match self {
2995            Self::Virtual(cursor) => cursor,
2996            _ => {
2997                mark_unlikely();
2998                panic!("Cursor is not a virtual cursor")
2999            }
3000        }
3001    }
3002
3003    pub fn as_materialized_view_mut(
3004        &mut self,
3005    ) -> &mut crate::incremental::cursor::MaterializedViewCursor {
3006        match self {
3007            Self::MaterializedView(cursor) => cursor,
3008            _ => {
3009                mark_unlikely();
3010                panic!("Cursor is not a materialized view cursor");
3011            }
3012        }
3013    }
3014
3015    pub fn as_index_method_mut(&mut self) -> &mut dyn IndexMethodCursor {
3016        match self {
3017            Self::IndexMethod(cursor) => cursor.as_mut(),
3018            _ => {
3019                mark_unlikely();
3020                panic!("Cursor is not an IndexMethod cursor");
3021            }
3022        }
3023    }
3024
3025    /// Move the cursor to a synthetic null row. See [Insn::NullRow]
3026    pub fn set_null_flag(&mut self, flag: bool) {
3027        match self {
3028            Self::BTree(cursor) => cursor.set_null_flag(flag),
3029            Self::Virtual(cursor) => cursor.set_null_flag(flag),
3030            _ => {
3031                mark_unlikely();
3032                panic!("set_null_flag on unexpected cursor type");
3033            }
3034        }
3035    }
3036}
3037
3038#[derive(Debug)]
3039#[must_use]
3040pub enum IOCompletions {
3041    Single(Completion),
3042}
3043
3044pub struct IOCompletionAsync<'a, I: ?Sized + IO> {
3045    io: &'a I,
3046    completion: Completion,
3047}
3048
3049impl<'a, I: ?Sized + IO> Future for IOCompletionAsync<'a, I> {
3050    type Output = Result<()>;
3051
3052    fn poll(
3053        mut self: std::pin::Pin<&mut Self>,
3054        cx: &mut std::task::Context<'_>,
3055    ) -> std::task::Poll<Self::Output> {
3056        let completion = std::pin::pin!(&mut self.as_mut().completion);
3057        match completion.poll(cx) {
3058            Poll::Pending => {
3059                self.io.step()?;
3060                Poll::Pending
3061            }
3062            res => res,
3063        }
3064    }
3065}
3066
3067impl IOCompletions {
3068    /// Wais for the Completions to complete
3069    pub fn wait<I: ?Sized + IO>(self, io: &I) -> Result<()> {
3070        match self {
3071            IOCompletions::Single(c) => io.wait_for_completion(c),
3072        }
3073    }
3074
3075    /// Waits for Completion to complete and `steps` IO. Ideally the user should do the stepping,
3076    /// but we do not have yet a good api for this
3077    pub async fn wait_async<I: ?Sized + IO>(self, io: &I) -> Result<()> {
3078        match self {
3079            IOCompletions::Single(c) => IOCompletionAsync { io, completion: c }.await,
3080        }
3081    }
3082
3083    pub fn finished(&self) -> bool {
3084        match self {
3085            IOCompletions::Single(c) => c.finished(),
3086        }
3087    }
3088
3089    /// Returns true if this is an explicit yield — a signal to return control
3090    /// to the cooperative scheduler so other fibers can make progress.
3091    pub fn is_explicit_yield(&self) -> bool {
3092        match self {
3093            IOCompletions::Single(c) => c.is_explicit_yield(),
3094        }
3095    }
3096
3097    /// Send abort signal to completions
3098    pub fn abort(&self) {
3099        match self {
3100            IOCompletions::Single(c) => c.abort(),
3101        }
3102    }
3103
3104    pub fn get_error(&self) -> Option<CompletionError> {
3105        match self {
3106            IOCompletions::Single(c) => c.get_error(),
3107        }
3108    }
3109
3110    pub fn set_waker(&self, waker: Option<&Waker>) {
3111        if let Some(waker) = waker {
3112            match self {
3113                IOCompletions::Single(c) => c.set_waker(waker),
3114            }
3115        }
3116    }
3117}
3118
3119#[derive(Debug)]
3120#[must_use]
3121pub enum IOResult<T> {
3122    Done(T),
3123    IO(IOCompletions),
3124}
3125
3126impl<T> IOResult<T> {
3127    #[inline]
3128    pub fn is_io(&self) -> bool {
3129        matches!(self, IOResult::IO(..))
3130    }
3131
3132    #[inline]
3133    pub fn io(self) -> Option<IOCompletions> {
3134        match self {
3135            IOResult::Done(_) => None,
3136            IOResult::IO(io) => Some(io),
3137        }
3138    }
3139
3140    #[inline]
3141    pub fn map<U>(self, func: impl FnOnce(T) -> U) -> IOResult<U> {
3142        match self {
3143            IOResult::Done(t) => IOResult::Done(func(t)),
3144            IOResult::IO(io) => IOResult::IO(io),
3145        }
3146    }
3147}
3148
3149/// Evaluate a Result<IOResult<T>>, if IO return IO.
3150#[macro_export]
3151macro_rules! return_if_io {
3152    ($expr:expr) => {
3153        match $expr {
3154            Ok(IOResult::Done(v)) => v,
3155            Ok(IOResult::IO(io)) => return Ok(IOResult::IO(io)),
3156            Err(err) => {
3157                branches::mark_unlikely();
3158                return Err(err);
3159            }
3160        }
3161    };
3162}
3163
3164#[macro_export]
3165macro_rules! return_and_restore_if_io {
3166    ($field:expr, $saved_state:expr, $e:expr) => {
3167        match $e {
3168            Ok(IOResult::Done(v)) => v,
3169            Ok(IOResult::IO(io)) => {
3170                let _ = std::mem::replace($field, $saved_state);
3171                return Ok(IOResult::IO(io));
3172            }
3173            Err(e) => {
3174                let _ = std::mem::replace($field, $saved_state);
3175                return Err(e);
3176            }
3177        }
3178    };
3179}
3180
3181#[derive(Debug, PartialEq, Clone, Copy)]
3182pub enum SeekResult {
3183    /// Record matching the [SeekOp] found in the B-tree and cursor was positioned to point onto that record
3184    Found,
3185    /// Record matching the [SeekOp] doesn't exists in the B-tree
3186    NotFound,
3187    /// This result can happen only if eq_only for [SeekOp] is false
3188    /// In this case Seek can position cursor to the leaf page boundaries (before the start, after the end)
3189    /// (e.g. if leaf page holds rows with keys from range [1..10], key 10 is absent and [SeekOp] is >= 10)
3190    ///
3191    /// turso-db has this extra [SeekResult] in order to make [BTreeCursor::seek] method to position cursor at
3192    /// the leaf of potential insertion, but also communicate to caller the fact that current cursor position
3193    /// doesn't hold a matching entry
3194    /// (necessary for Seek{XX} VM op-codes, so these op-codes will try to advance cursor in order to move it to matching entry)
3195    TryAdvance,
3196}
3197
3198#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3199/// The match condition of a table/index seek.
3200pub enum SeekOp {
3201    /// If eq_only is true, this means in practice:
3202    /// We are iterating forwards, but we are really looking for an exact match on the seek key.
3203    GE {
3204        eq_only: bool,
3205    },
3206    GT,
3207    /// If eq_only is true, this means in practice:
3208    /// We are iterating backwards, but we are really looking for an exact match on the seek key.
3209    LE {
3210        eq_only: bool,
3211    },
3212    LT,
3213}
3214
3215impl SeekOp {
3216    /// A given seek op implies an iteration direction.
3217    ///
3218    /// For example, a seek with SeekOp::GT implies:
3219    /// Find the first table/index key that compares greater than the seek key
3220    /// -> used in forwards iteration.
3221    ///
3222    /// A seek with SeekOp::LE implies:
3223    /// Find the last table/index key that compares less than or equal to the seek key
3224    /// -> used in backwards iteration.
3225    #[inline(always)]
3226    pub fn iteration_direction(&self) -> IterationDirection {
3227        match self {
3228            SeekOp::GE { .. } | SeekOp::GT => IterationDirection::Forwards,
3229            SeekOp::LE { .. } | SeekOp::LT => IterationDirection::Backwards,
3230        }
3231    }
3232
3233    pub fn eq_only(&self) -> bool {
3234        match self {
3235            SeekOp::GE { eq_only } | SeekOp::LE { eq_only } => *eq_only,
3236            _ => false,
3237        }
3238    }
3239
3240    pub fn reverse(&self) -> Self {
3241        match self {
3242            SeekOp::GE { eq_only } => SeekOp::LE { eq_only: *eq_only },
3243            SeekOp::GT => SeekOp::LT,
3244            SeekOp::LE { eq_only } => SeekOp::GE { eq_only: *eq_only },
3245            SeekOp::LT => SeekOp::GT,
3246        }
3247    }
3248}
3249
3250#[derive(Clone, PartialEq, Debug)]
3251pub enum SeekKey<'a> {
3252    TableRowId(i64),
3253    IndexKey(&'a ImmutableRecord),
3254}
3255
3256#[derive(Debug)]
3257pub enum DatabaseChangeType {
3258    Delete,
3259    Update { bin_record: std::vec::Vec<u8> },
3260    Insert { bin_record: std::vec::Vec<u8> },
3261}
3262
3263#[derive(Debug)]
3264pub struct DatabaseChange {
3265    pub change_id: i64,
3266    pub change_time: u64,
3267    pub change: DatabaseChangeType,
3268    pub table_name: String,
3269    pub id: i64,
3270}
3271
3272#[derive(Debug)]
3273pub struct WalFrameInfo {
3274    pub page_no: u32,
3275    pub db_size: u32,
3276}
3277
3278#[derive(Debug, PartialEq)]
3279pub struct WalState {
3280    pub checkpoint_seq_no: u32,
3281    pub max_frame: u64,
3282}
3283
3284impl WalFrameInfo {
3285    pub fn is_commit_frame(&self) -> bool {
3286        self.db_size > 0
3287    }
3288    pub fn from_frame_header(frame: &[u8]) -> Self {
3289        let page_no = u32::from_be_bytes(frame[0..4].try_into().unwrap());
3290        let db_size = u32::from_be_bytes(frame[4..8].try_into().unwrap());
3291        Self { page_no, db_size }
3292    }
3293    pub fn put_to_frame_header(&self, frame: &mut [u8]) {
3294        frame[0..4].copy_from_slice(&self.page_no.to_be_bytes());
3295        frame[4..8].copy_from_slice(&self.db_size.to_be_bytes());
3296    }
3297}
3298
3299#[cfg(clt_turso_tests)]
3300mod tests {
3301    use super::*;
3302    use crate::alloc::vec;
3303    use crate::translate::collate::CollationSeq;
3304
3305    #[test]
3306    fn test_value_iterator_simple() {
3307        let mut buf = std::vec::Vec::new();
3308        let record = Record::new(vec![Value::from_i64(42), Value::Text(Text::new("hello"))]);
3309        record.serialize(&mut buf);
3310
3311        let iter = ValueIterator::new(&buf).unwrap();
3312        assert!(!iter.is_empty());
3313        assert_eq!(iter.clone().count(), 2);
3314
3315        let mut iter = ValueIterator::new(&buf).unwrap();
3316
3317        let val = iter.next().unwrap().unwrap();
3318        assert_eq!(val, ValueRef::from_i64(42));
3319
3320        let val = iter.next().unwrap().unwrap();
3321        assert_eq!(
3322            val,
3323            ValueRef::Text(TextRef::new("hello", TextSubtype::Text))
3324        );
3325
3326        assert!(iter.next().is_none());
3327    }
3328
3329    #[test]
3330    fn test_value_iterator_nulls() {
3331        let mut buf = std::vec::Vec::new();
3332        let record = Record::new(vec![Value::Null, Value::Null, Value::Null]);
3333        record.serialize(&mut buf);
3334
3335        let iter = ValueIterator::new(&buf).unwrap();
3336
3337        for val in iter {
3338            assert_eq!(val.unwrap(), ValueRef::Null);
3339        }
3340    }
3341
3342    #[test]
3343    fn test_value_iterator_mixed_types() {
3344        let mut buf = std::vec::Vec::new();
3345        let record = Record::new(vec![
3346            Value::Null,
3347            Value::from_i64(100),
3348            Value::from_f64(std::f64::consts::PI),
3349            Value::Text(Text::new("test")),
3350            Value::Blob(std::vec![1, 2, 3]),
3351            Value::from_i64(0),
3352            Value::from_i64(1),
3353        ]);
3354        record.serialize(&mut buf);
3355
3356        let iter = ValueIterator::new(&buf).unwrap();
3357        let values: Vec<_> = iter.try_collect::<Result<Vec<_>>>().unwrap().unwrap();
3358
3359        assert_eq!(values[0], ValueRef::Null);
3360        assert_eq!(values[1], ValueRef::from_i64(100));
3361        assert_eq!(values[2], ValueRef::from_f64(std::f64::consts::PI));
3362        assert_eq!(
3363            values[3],
3364            ValueRef::Text(TextRef::new("test", TextSubtype::Text))
3365        );
3366        assert_eq!(values[4], ValueRef::Blob(&[1, 2, 3]));
3367        assert_eq!(values[5], ValueRef::from_i64(0));
3368        assert_eq!(values[6], ValueRef::from_i64(1));
3369    }
3370
3371    #[test]
3372    fn test_value_iterator_large_record() {
3373        let mut buf = std::vec::Vec::new();
3374        let values: Vec<Value> = (0..20)
3375            .map(|i| Value::from_i64(i as i64))
3376            .try_collect()
3377            .unwrap();
3378        let record = Record::new(values);
3379        record.serialize(&mut buf);
3380
3381        let iter = ValueIterator::new(&buf).unwrap();
3382        assert_eq!(iter.count(), 20);
3383
3384        let iter = ValueIterator::new(&buf).unwrap();
3385        for (i, val) in iter.enumerate() {
3386            assert_eq!(val.unwrap(), ValueRef::from_i64(i as i64));
3387        }
3388    }
3389
3390    #[test]
3391    fn test_value_iterator_zero_allocation() {
3392        let mut buf = std::vec::Vec::new();
3393        let values: Vec<Value> = (0..5)
3394            .map(|i| Value::from_i64(i as i64))
3395            .try_collect()
3396            .unwrap();
3397        let record = Record::new(values);
3398        record.serialize(&mut buf);
3399
3400        let mut iter = ValueIterator::new(&buf).unwrap();
3401        let _ = iter.next();
3402        let _ = iter.next();
3403    }
3404
3405    pub fn compare_immutable_for_testing(
3406        l: &[ValueRef],
3407        r: &[ValueRef],
3408        index_key_info: &[KeyInfo],
3409        tie_breaker: std::cmp::Ordering,
3410    ) -> std::cmp::Ordering {
3411        let min_len = l.len().min(r.len());
3412
3413        for i in 0..min_len {
3414            let column_order = index_key_info[i].sort_order;
3415            let collation = index_key_info[i].collation;
3416
3417            let cmp = match (&l[i], &r[i]) {
3418                (ValueRef::Text(left), ValueRef::Text(right)) => {
3419                    collation.compare_strings(left, right)
3420                }
3421                _ => l[i].partial_cmp(&r[i]).unwrap_or(std::cmp::Ordering::Equal),
3422            };
3423
3424            if cmp != std::cmp::Ordering::Equal {
3425                return match column_order {
3426                    SortOrder::Asc => cmp,
3427                    SortOrder::Desc => cmp.reverse(),
3428                };
3429            }
3430        }
3431
3432        tie_breaker
3433    }
3434
3435    fn create_record(values: Vec<Value>) -> ImmutableRecord {
3436        let registers: Vec<Register> = values
3437            .into_iter()
3438            .map(Register::Value)
3439            .try_collect()
3440            .unwrap();
3441        ImmutableRecord::from_registers(&registers, registers.len()).unwrap()
3442    }
3443
3444    #[test]
3445    fn immutable_record_ref_borrows_bin_record_payload() {
3446        let expected_values = vec![Value::from_i64(42), Value::build_text("borrowed")];
3447        let record = create_record(expected_values.clone());
3448        let payload = record.get_payload();
3449
3450        let borrowed = ImmutableRecordRef::from_bin_record(payload);
3451
3452        assert_eq!(borrowed.get_payload().as_ptr(), payload.as_ptr());
3453        assert_eq!(borrowed.column_count(), 2);
3454        assert_eq!(borrowed.get_values_owned().unwrap(), expected_values);
3455    }
3456
3457    fn create_index_info(
3458        num_cols: usize,
3459        sort_orders: Vec<SortOrder>,
3460        collations: Vec<CollationSeq>,
3461    ) -> IndexInfo {
3462        IndexInfo::new(
3463            sort_orders
3464                .into_iter()
3465                .zip(collations)
3466                .map(|(sort_order, collation)| KeyInfo {
3467                    sort_order,
3468                    collation,
3469                    nulls_order: None,
3470                }),
3471            false,
3472            num_cols,
3473            false,
3474        )
3475        .unwrap()
3476    }
3477
3478    fn assert_compare_matches_full_comparison(
3479        serialized_values: Vec<Value>,
3480        unpacked_values: Vec<ValueRef>,
3481        index_info: &IndexInfo,
3482        test_name: &str,
3483    ) {
3484        let serialized = create_record(serialized_values.clone());
3485
3486        let serialized_ref_values: Vec<ValueRef> = serialized_values
3487            .iter()
3488            .map(Value::as_ref)
3489            .try_collect()
3490            .unwrap();
3491
3492        let tie_breaker = std::cmp::Ordering::Equal;
3493
3494        let gold_result = compare_immutable_for_testing(
3495            &serialized_ref_values,
3496            &unpacked_values,
3497            &index_info.key_info,
3498            tie_breaker,
3499        );
3500
3501        let comparer = find_compare(unpacked_values.iter().peekable(), index_info);
3502        let optimized_result = comparer
3503            .compare(&serialized, &unpacked_values, index_info, 0, tie_breaker)
3504            .unwrap();
3505
3506        assert_eq!(
3507            gold_result, optimized_result,
3508            "Test '{test_name}' failed: Full Comparison: {gold_result:?}, Optimized: {optimized_result:?}, Strategy: {comparer:?}"
3509        );
3510
3511        let generic_result = compare_records_generic(
3512            &serialized,
3513            unpacked_values.iter(),
3514            index_info,
3515            0,
3516            tie_breaker,
3517        )
3518        .unwrap();
3519        assert_eq!(
3520            gold_result, generic_result,
3521            "Test '{test_name}' failed with generic: Full Comparison: {gold_result:?}, Generic: {generic_result:?}\n LHS: {serialized_values:?}\n RHS: {unpacked_values:?}"
3522        );
3523    }
3524
3525    #[test]
3526    fn test_calc_header_size() {
3527        // Test 1-byte header size (serial type sizes 0 to 126)
3528        const MIN_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER: usize = 0;
3529        assert_eq!(
3530            Record::calc_header_size(MIN_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER),
3531            MIN_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER + 1
3532        );
3533        const BITS_7_MAX: usize = (1 << 7) - 1; // varints use 7 bits for the value and 1 continuation bit
3534        const MAX_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER: usize = BITS_7_MAX - 1;
3535        assert_eq!(
3536            Record::calc_header_size(MAX_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER),
3537            MAX_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER + 1
3538        );
3539
3540        // Test 2-byte header size (serial type sizes 127 to 16381)
3541        const MIN_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER: usize =
3542            MAX_SERIALTYPES_SIZE_FOR_1_BYTE_HEADER + 1;
3543        assert_eq!(
3544            Record::calc_header_size(MIN_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER),
3545            MIN_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER + 2
3546        );
3547        const BITS_14_MAX: usize = (1 << 14) - 1;
3548        const MAX_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER: usize = BITS_14_MAX - 2;
3549        assert_eq!(
3550            Record::calc_header_size(MAX_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER),
3551            MAX_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER + 2
3552        );
3553
3554        // Test 3-byte header size (serial type sizes 16382 to 2097148)
3555        const MIN_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER: usize =
3556            MAX_SERIALTYPES_SIZE_FOR_2_BYTE_HEADER + 1;
3557        assert_eq!(
3558            Record::calc_header_size(MIN_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER),
3559            MIN_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER + 3
3560        );
3561        const BITS_21_MAX: usize = (1 << 21) - 1;
3562        const MAX_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER: usize = BITS_21_MAX - 3;
3563        assert_eq!(
3564            Record::calc_header_size(MAX_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER),
3565            MAX_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER + 3
3566        );
3567
3568        // Test 4-byte header size (serial type sizes 2097149 to 268435451)
3569        const MIN_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER: usize =
3570            MAX_SERIALTYPES_SIZE_FOR_3_BYTE_HEADER + 1;
3571        assert_eq!(
3572            Record::calc_header_size(MIN_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER),
3573            MIN_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER + 4
3574        );
3575        const BITS_28_MAX: usize = (1 << 28) - 1;
3576        const MAX_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER: usize = BITS_28_MAX - 4;
3577        assert_eq!(
3578            Record::calc_header_size(MAX_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER),
3579            MAX_SERIALTYPES_SIZE_FOR_4_BYTE_HEADER + 4
3580        );
3581    }
3582
3583    #[test]
3584    fn test_integer_fast_path() {
3585        let index_info = create_index_info(
3586            2,
3587            vec![SortOrder::Asc, SortOrder::Asc],
3588            vec![CollationSeq::Binary; 2],
3589        );
3590
3591        let test_cases = vec![
3592            (
3593                vec![Value::from_i64(42)],
3594                vec![ValueRef::from_i64(42)],
3595                "equal_integers",
3596            ),
3597            (
3598                vec![Value::from_i64(10)],
3599                vec![ValueRef::from_i64(20)],
3600                "less_than_integers",
3601            ),
3602            (
3603                vec![Value::from_i64(30)],
3604                vec![ValueRef::from_i64(20)],
3605                "greater_than_integers",
3606            ),
3607            (
3608                vec![Value::from_i64(0)],
3609                vec![ValueRef::from_i64(0)],
3610                "zero_integers",
3611            ),
3612            (
3613                vec![Value::from_i64(-5)],
3614                vec![ValueRef::from_i64(-5)],
3615                "negative_integers",
3616            ),
3617            (
3618                vec![Value::from_i64(i64::MAX)],
3619                vec![ValueRef::from_i64(i64::MAX)],
3620                "max_integers",
3621            ),
3622            (
3623                vec![Value::from_i64(i64::MIN)],
3624                vec![ValueRef::from_i64(i64::MIN)],
3625                "min_integers",
3626            ),
3627            (
3628                vec![Value::from_i64(42), Value::Text(Text::new("hello"))],
3629                vec![
3630                    ValueRef::from_i64(42),
3631                    ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3632                ],
3633                "integer_text_equal",
3634            ),
3635            (
3636                vec![Value::from_i64(42), Value::Text(Text::new("hello"))],
3637                vec![
3638                    ValueRef::from_i64(42),
3639                    ValueRef::Text(TextRef::new("world", TextSubtype::Text)),
3640                ],
3641                "integer_equal_text_different",
3642            ),
3643        ];
3644
3645        for (serialized_values, unpacked_values, test_name) in test_cases {
3646            println!(
3647                "Testing integer fast path `{test_name}`\nLHS: {serialized_values:?}\nRHS: {unpacked_values:?}"
3648            );
3649            assert_compare_matches_full_comparison(
3650                serialized_values,
3651                unpacked_values,
3652                &index_info,
3653                test_name,
3654            );
3655        }
3656    }
3657
3658    #[test]
3659    fn test_string_fast_path() {
3660        let index_info = create_index_info(
3661            2,
3662            vec![SortOrder::Asc, SortOrder::Asc],
3663            vec![CollationSeq::Binary; 2],
3664        );
3665
3666        let test_cases = vec![
3667            (
3668                vec![Value::Text(Text::new("hello"))],
3669                vec![ValueRef::Text(TextRef::new("hello", TextSubtype::Text))],
3670                "equal_strings",
3671            ),
3672            (
3673                vec![Value::Text(Text::new("abc"))],
3674                vec![ValueRef::Text(TextRef::new("def", TextSubtype::Text))],
3675                "less_than_strings",
3676            ),
3677            (
3678                vec![Value::Text(Text::new("xyz"))],
3679                vec![ValueRef::Text(TextRef::new("abc", TextSubtype::Text))],
3680                "greater_than_strings",
3681            ),
3682            (
3683                vec![Value::Text(Text::new(""))],
3684                vec![ValueRef::Text(TextRef::new("", TextSubtype::Text))],
3685                "empty_strings",
3686            ),
3687            (
3688                vec![Value::Text(Text::new("a"))],
3689                vec![ValueRef::Text(TextRef::new("aa", TextSubtype::Text))],
3690                "prefix_strings",
3691            ),
3692            // Multi-field with string first
3693            (
3694                vec![Value::Text(Text::new("hello")), Value::from_i64(42)],
3695                vec![
3696                    ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3697                    ValueRef::from_i64(42),
3698                ],
3699                "string_integer_equal",
3700            ),
3701            (
3702                vec![Value::Text(Text::new("hello")), Value::from_i64(42)],
3703                vec![
3704                    ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3705                    ValueRef::from_i64(99),
3706                ],
3707                "string_equal_integer_different",
3708            ),
3709        ];
3710
3711        for (serialized_values, unpacked_values, test_name) in test_cases {
3712            assert_compare_matches_full_comparison(
3713                serialized_values,
3714                unpacked_values,
3715                &index_info,
3716                test_name,
3717            );
3718        }
3719    }
3720
3721    #[test]
3722    fn test_type_precedence() {
3723        let index_info = create_index_info(1, vec![SortOrder::Asc], vec![CollationSeq::Binary]);
3724
3725        // Test SQLite type precedence: NULL < Numbers < Text < Blob
3726        let test_cases = vec![
3727            // NULL vs others
3728            (
3729                vec![Value::Null],
3730                vec![ValueRef::from_i64(42)],
3731                "null_vs_integer",
3732            ),
3733            (
3734                vec![Value::Null],
3735                vec![ValueRef::from_f64(64.4)],
3736                "null_vs_float",
3737            ),
3738            (
3739                vec![Value::Null],
3740                vec![ValueRef::Text(TextRef::new("hello", TextSubtype::Text))],
3741                "null_vs_text",
3742            ),
3743            (
3744                vec![Value::Null],
3745                vec![ValueRef::Blob(b"blob")],
3746                "null_vs_blob",
3747            ),
3748            // Numbers vs Text/Blob
3749            (
3750                vec![Value::from_i64(42)],
3751                vec![ValueRef::Text(TextRef::new("hello", TextSubtype::Text))],
3752                "integer_vs_text",
3753            ),
3754            (
3755                vec![Value::from_f64(64.4)],
3756                vec![ValueRef::Text(TextRef::new("hello", TextSubtype::Text))],
3757                "float_vs_text",
3758            ),
3759            (
3760                vec![Value::from_i64(42)],
3761                vec![ValueRef::Blob(b"blob")],
3762                "integer_vs_blob",
3763            ),
3764            (
3765                vec![Value::from_f64(64.4)],
3766                vec![ValueRef::Blob(b"blob")],
3767                "float_vs_blob",
3768            ),
3769            // Text vs Blob
3770            (
3771                vec![Value::Text(Text::new("hello"))],
3772                vec![ValueRef::Blob(b"blob")],
3773                "text_vs_blob",
3774            ),
3775            // Integer vs Float (affinity conversion)
3776            (
3777                vec![Value::from_i64(42)],
3778                vec![ValueRef::from_f64(42.0)],
3779                "integer_vs_equal_float",
3780            ),
3781            (
3782                vec![Value::from_i64(42)],
3783                vec![ValueRef::from_f64(42.5)],
3784                "integer_vs_different_float",
3785            ),
3786            (
3787                vec![Value::from_f64(42.5)],
3788                vec![ValueRef::from_i64(42)],
3789                "float_vs_integer",
3790            ),
3791        ];
3792
3793        for (serialized_values, unpacked_values, test_name) in test_cases {
3794            assert_compare_matches_full_comparison(
3795                serialized_values,
3796                unpacked_values,
3797                &index_info,
3798                test_name,
3799            );
3800        }
3801    }
3802
3803    #[test]
3804    fn test_sort_order_desc() {
3805        let index_info = create_index_info(
3806            2,
3807            vec![SortOrder::Desc, SortOrder::Asc],
3808            vec![CollationSeq::Binary; 2],
3809        );
3810
3811        let test_cases = vec![
3812            // DESC order should reverse first field comparison
3813            (
3814                vec![Value::from_i64(10)],
3815                vec![ValueRef::from_i64(20)],
3816                "desc_integer_reversed",
3817            ),
3818            (
3819                vec![Value::Text(Text::new("abc"))],
3820                vec![ValueRef::Text(TextRef::new("def", TextSubtype::Text))],
3821                "desc_string_reversed",
3822            ),
3823            // Mixed sort orders
3824            (
3825                vec![Value::from_i64(10), Value::Text(Text::new("hello"))],
3826                vec![
3827                    ValueRef::from_i64(20),
3828                    ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3829                ],
3830                "desc_first_asc_second",
3831            ),
3832        ];
3833
3834        for (serialized_values, unpacked_values, test_name) in test_cases {
3835            assert_compare_matches_full_comparison(
3836                serialized_values,
3837                unpacked_values,
3838                &index_info,
3839                test_name,
3840            );
3841        }
3842    }
3843
3844    #[test]
3845    fn test_edge_cases() {
3846        let index_info =
3847            create_index_info(15, vec![SortOrder::Asc; 15], vec![CollationSeq::Binary; 15]);
3848
3849        let test_cases = vec![
3850            (
3851                vec![Value::from_i64(42)],
3852                vec![
3853                    ValueRef::from_i64(42),
3854                    ValueRef::Text(TextRef::new("extra", TextSubtype::Text)),
3855                ],
3856                "fewer_serialized_fields",
3857            ),
3858            (
3859                vec![Value::from_i64(42), Value::Text(Text::new("extra"))],
3860                vec![ValueRef::from_i64(42)],
3861                "fewer_unpacked_fields",
3862            ),
3863            (vec![], vec![], "both_empty"),
3864            (vec![], vec![ValueRef::from_i64(42)], "empty_serialized"),
3865            (
3866                (0..15).map(Value::from_i64).try_collect().unwrap(),
3867                (0..15).map(ValueRef::from_i64).try_collect().unwrap(),
3868                "large_field_count",
3869            ),
3870            (
3871                vec![Value::Blob(std::vec![1, 2, 3])],
3872                vec![ValueRef::Blob(&[1, 2, 3])],
3873                "blob_first_field",
3874            ),
3875            (
3876                vec![Value::Text(Text::new("hello")), Value::from_i64(5)],
3877                vec![ValueRef::Text(TextRef::new("hello", TextSubtype::Text))],
3878                "equal_text_prefix_but_more_serialized_fields",
3879            ),
3880            (
3881                vec![Value::Text(Text::new("same")), Value::from_i64(5)],
3882                vec![
3883                    ValueRef::Text(TextRef::new("same", TextSubtype::Text)),
3884                    ValueRef::from_i64(5),
3885                ],
3886                "equal_text_then_equal_int",
3887            ),
3888        ];
3889
3890        for (serialized_values, unpacked_values, test_name) in test_cases {
3891            assert_compare_matches_full_comparison(
3892                serialized_values,
3893                unpacked_values,
3894                &index_info,
3895                test_name,
3896            );
3897        }
3898    }
3899
3900    #[test]
3901    fn test_skip_parameter() {
3902        let index_info = create_index_info(
3903            3,
3904            vec![SortOrder::Asc, SortOrder::Asc, SortOrder::Asc],
3905            vec![CollationSeq::Binary; 3],
3906        );
3907
3908        let serialized = create_record(vec![
3909            Value::from_i64(1),
3910            Value::from_i64(2),
3911            Value::from_i64(3),
3912        ]);
3913        let unpacked = [
3914            ValueRef::from_i64(1),
3915            ValueRef::from_i64(99),
3916            ValueRef::from_i64(3),
3917        ];
3918
3919        let tie_breaker = std::cmp::Ordering::Equal;
3920        let result_skip_0 =
3921            compare_records_generic(&serialized, unpacked.iter(), &index_info, 0, tie_breaker)
3922                .unwrap();
3923        let result_skip_1 =
3924            compare_records_generic(&serialized, unpacked.iter(), &index_info, 1, tie_breaker)
3925                .unwrap();
3926
3927        assert_eq!(result_skip_0, std::cmp::Ordering::Less);
3928
3929        assert_eq!(result_skip_1, std::cmp::Ordering::Less);
3930    }
3931
3932    #[test]
3933    fn test_strategy_selection() {
3934        let collations_small = vec![CollationSeq::Binary; 3];
3935        let collations_large = vec![CollationSeq::Binary; 15];
3936        let index_info_small = create_index_info(
3937            3,
3938            vec![SortOrder::Asc, SortOrder::Asc, SortOrder::Asc],
3939            collations_small,
3940        );
3941        let index_info_large = create_index_info(15, vec![SortOrder::Asc; 15], collations_large);
3942
3943        let int_values = [
3944            ValueRef::from_i64(42),
3945            ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3946        ];
3947        assert!(matches!(
3948            find_compare(int_values.iter().peekable(), &index_info_small),
3949            RecordCompare::Int
3950        ));
3951
3952        let string_values = [
3953            ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
3954            ValueRef::from_i64(42),
3955        ];
3956        assert!(matches!(
3957            find_compare(string_values.iter().peekable(), &index_info_small),
3958            RecordCompare::String
3959        ));
3960
3961        let large_values: Vec<ValueRef> = (0..15).map(ValueRef::from_i64).try_collect().unwrap();
3962        assert!(matches!(
3963            find_compare(large_values.iter().peekable(), &index_info_large),
3964            RecordCompare::Generic
3965        ));
3966
3967        let blob_values = [ValueRef::Blob(&[1, 2, 3])];
3968        assert!(matches!(
3969            find_compare(blob_values.iter().peekable(), &index_info_small),
3970            RecordCompare::Generic
3971        ));
3972    }
3973
3974    #[test]
3975    fn test_serialize_null() {
3976        let record = Record::new(vec![Value::Null]);
3977        let mut buf = std::vec::Vec::new();
3978        record.serialize(&mut buf);
3979
3980        let header_length = record.values.len() + 1;
3981        let header = &buf[0..header_length];
3982        // First byte should be header size
3983        assert_eq!(header[0], header_length as u8);
3984        // Second byte should be serial type for NULL
3985        assert_eq!(header[1] as u64, u64::from(SerialType::null()));
3986        // Check that the buffer is empty after the header
3987        assert_eq!(buf.len(), header_length);
3988    }
3989
3990    #[test]
3991    fn test_serialize_integers() {
3992        let record = Record::new(vec![
3993            Value::from_i64(0),                 // Should use ConstInt0
3994            Value::from_i64(1),                 // Should use ConstInt1
3995            Value::from_i64(42),                // Should use SERIAL_TYPE_I8
3996            Value::from_i64(1000),              // Should use SERIAL_TYPE_I16
3997            Value::from_i64(1_000_000),         // Should use SERIAL_TYPE_I24
3998            Value::from_i64(1_000_000_000),     // Should use SERIAL_TYPE_I32
3999            Value::from_i64(1_000_000_000_000), // Should use SERIAL_TYPE_I48
4000            Value::from_i64(i64::MAX),          // Should use SERIAL_TYPE_I64
4001        ]);
4002        let mut buf = std::vec::Vec::new();
4003        record.serialize(&mut buf);
4004
4005        let header_length = record.values.len() + 1;
4006        let header = &buf[0..header_length];
4007        // First byte should be header size
4008        assert_eq!(header[0], header_length as u8); // Header should be larger than number of values
4009
4010        // Check that correct serial types were chosen
4011        assert_eq!(header[1] as u64, u64::from(SerialType::const_int0())); // 8
4012        assert_eq!(header[2] as u64, u64::from(SerialType::const_int1())); // 9
4013        assert_eq!(header[3] as u64, u64::from(SerialType::i8())); // 1
4014        assert_eq!(header[4] as u64, u64::from(SerialType::i16())); // 2
4015        assert_eq!(header[5] as u64, u64::from(SerialType::i24())); // 3
4016        assert_eq!(header[6] as u64, u64::from(SerialType::i32())); // 4
4017        assert_eq!(header[7] as u64, u64::from(SerialType::i48())); // 5
4018        assert_eq!(header[8] as u64, u64::from(SerialType::i64())); // 6
4019
4020        // test that the bytes after the header can be interpreted as the correct values
4021        let mut cur_offset = header_length;
4022
4023        // Value::from_i64(0) - ConstInt0: NO PAYLOAD BYTES
4024        // Value::from_i64(1) - ConstInt1: NO PAYLOAD BYTES
4025
4026        // Value::from_i64(42) - I8: 1 byte
4027        let i8_bytes = &buf[cur_offset..cur_offset + size_of::<i8>()];
4028        cur_offset += size_of::<i8>();
4029
4030        // Value::from_i64(1000) - I16: 2 bytes
4031        let i16_bytes = &buf[cur_offset..cur_offset + size_of::<i16>()];
4032        cur_offset += size_of::<i16>();
4033
4034        // Value::from_i64(1_000_000) - I24: 3 bytes
4035        let i24_bytes = &buf[cur_offset..cur_offset + 3];
4036        cur_offset += 3;
4037
4038        // Value::from_i64(1_000_000_000) - I32: 4 bytes
4039        let i32_bytes = &buf[cur_offset..cur_offset + size_of::<i32>()];
4040        cur_offset += size_of::<i32>();
4041
4042        // Value::from_i64(1_000_000_000_000) - I48: 6 bytes
4043        let i48_bytes = &buf[cur_offset..cur_offset + 6];
4044        cur_offset += 6;
4045
4046        // Value::from_i64(i64::MAX) - I64: 8 bytes
4047        let i64_bytes = &buf[cur_offset..cur_offset + size_of::<i64>()];
4048
4049        // Verify the payload values
4050        let val_int8 = i8::from_be_bytes(i8_bytes.try_into().unwrap());
4051        let val_int16 = i16::from_be_bytes(i16_bytes.try_into().unwrap());
4052
4053        let mut i24_with_padding = vec![0];
4054        i24_with_padding.extend(i24_bytes);
4055        let val_int24 = i32::from_be_bytes(i24_with_padding.try_into().unwrap());
4056
4057        let val_int32 = i32::from_be_bytes(i32_bytes.try_into().unwrap());
4058
4059        let mut i48_with_padding = vec![0, 0];
4060        i48_with_padding.extend(i48_bytes);
4061        let val_int48 = i64::from_be_bytes(i48_with_padding.try_into().unwrap());
4062
4063        let val_int64 = i64::from_be_bytes(i64_bytes.try_into().unwrap());
4064
4065        assert_eq!(val_int8, 42);
4066        assert_eq!(val_int16, 1000);
4067        assert_eq!(val_int24, 1_000_000);
4068        assert_eq!(val_int32, 1_000_000_000);
4069        assert_eq!(val_int48, 1_000_000_000_000);
4070        assert_eq!(val_int64, i64::MAX);
4071
4072        //Size of buffer = header + payload bytes
4073        // ConstInt0 and ConstInt1 contribute 0 bytes to payload
4074        assert_eq!(
4075            buf.len(),
4076            header_length  // 9 bytes (header size + 8 serial types)
4077                + size_of::<i8>()        // I8: 1 byte
4078                + size_of::<i16>()        // I16: 2 bytes
4079                + (size_of::<i32>() - 1)        // I24: 3 bytes
4080                + size_of::<i32>()        // I32: 4 bytes
4081                + (size_of::<i64>() - 2)        // I48: 6 bytes
4082                + size_of::<i64>() // I64: 8 bytes
4083        );
4084    }
4085
4086    #[test]
4087    fn test_serialize_const_integers() {
4088        let record = Record::new(vec![Value::from_i64(0), Value::from_i64(1)]);
4089        let mut buf = std::vec::Vec::new();
4090        record.serialize(&mut buf);
4091
4092        // [header_size, serial_type_0, serial_type_1] + no payload bytes
4093        let expected_header_size = 3; // 1 byte for header size + 2 bytes for serial types
4094
4095        assert_eq!(buf.len(), expected_header_size);
4096
4097        // Check header size
4098        assert_eq!(buf[0], expected_header_size as u8);
4099
4100        assert_eq!(buf[1] as u64, u64::from(SerialType::const_int0())); // Should be 8
4101        assert_eq!(buf[2] as u64, u64::from(SerialType::const_int1())); // Should be 9
4102
4103        assert_eq!(buf[1], 8); // ConstInt0 serial type
4104        assert_eq!(buf[2], 9); // ConstInt1 serial type
4105    }
4106
4107    #[test]
4108    fn test_serialize_single_const_int0() {
4109        let record = Record::new(vec![Value::from_i64(0)]);
4110        let mut buf = std::vec::Vec::new();
4111        record.serialize(&mut buf);
4112
4113        // Expected: [header_size=2, serial_type=8]
4114        assert_eq!(buf.len(), 2);
4115        assert_eq!(buf[0], 2); // Header size
4116        assert_eq!(buf[1], 8); // ConstInt0 serial type
4117    }
4118
4119    #[test]
4120    fn test_serialize_float() {
4121        #[warn(clippy::approx_constant)]
4122        let record = Record::new(vec![Value::from_f64(3.15555)]);
4123        let mut buf = std::vec::Vec::new();
4124        record.serialize(&mut buf);
4125
4126        let header_length = record.values.len() + 1;
4127        let header = &buf[0..header_length];
4128        assert_eq!(header[0], header_length as u8);
4129        // Second byte should be serial type for FLOAT
4130        assert_eq!(header[1] as u64, u64::from(SerialType::f64()));
4131        // Check that the bytes after the header can be interpreted as the float
4132        let float_bytes = &buf[header_length..header_length + size_of::<f64>()];
4133        let float = f64::from_be_bytes(float_bytes.try_into().unwrap());
4134        assert_eq!(float, 3.15555);
4135        // Check that buffer length is correct
4136        assert_eq!(buf.len(), header_length + size_of::<f64>());
4137    }
4138
4139    #[test]
4140    fn test_serialize_text() {
4141        let text = "hello";
4142        let record = Record::new(vec![Value::Text(Text::new(text))]);
4143        let mut buf = std::vec::Vec::new();
4144        record.serialize(&mut buf);
4145
4146        let header_length = record.values.len() + 1;
4147        let header = &buf[0..header_length];
4148        // First byte should be header size
4149        assert_eq!(header[0], header_length as u8);
4150        // Second byte should be serial type for TEXT, which is (len * 2 + 13)
4151        assert_eq!(header[1], (5 * 2 + 13) as u8);
4152        // Check the actual text bytes
4153        assert_eq!(&buf[2..7], b"hello");
4154        // Check that buffer length is correct
4155        assert_eq!(buf.len(), header_length + text.len());
4156    }
4157
4158    #[test]
4159    fn test_serialize_blob() {
4160        let blob = std::vec![1, 2, 3, 4, 5];
4161        let record = Record::new(vec![Value::Blob(blob.clone())]);
4162        let mut buf = std::vec::Vec::new();
4163        record.serialize(&mut buf);
4164
4165        let header_length = record.values.len() + 1;
4166        let header = &buf[0..header_length];
4167        // First byte should be header size
4168        assert_eq!(header[0], header_length as u8);
4169        // Second byte should be serial type for BLOB, which is (len * 2 + 12)
4170        assert_eq!(header[1], (5 * 2 + 12) as u8);
4171        // Check the actual blob bytes
4172        assert_eq!(&buf[2..7], &[1, 2, 3, 4, 5]);
4173        // Check that buffer length is correct
4174        assert_eq!(buf.len(), header_length + blob.len());
4175    }
4176
4177    #[test]
4178    fn test_serialize_mixed_types() {
4179        let text = "test";
4180        let record = Record::new(vec![
4181            Value::Null,
4182            Value::from_i64(42),
4183            Value::from_f64(3.15),
4184            Value::Text(Text::new(text)),
4185        ]);
4186        let mut buf = std::vec::Vec::new();
4187        record.serialize(&mut buf);
4188
4189        let header_length = record.values.len() + 1;
4190        let header = &buf[0..header_length];
4191        // First byte should be header size
4192        assert_eq!(header[0], header_length as u8);
4193        // Second byte should be serial type for NULL
4194        assert_eq!(header[1] as u64, u64::from(SerialType::null()));
4195        // Third byte should be serial type for I8
4196        assert_eq!(header[2] as u64, u64::from(SerialType::i8()));
4197        // Fourth byte should be serial type for F64
4198        assert_eq!(header[3] as u64, u64::from(SerialType::f64()));
4199        // Fifth byte should be serial type for TEXT, which is (len * 2 + 13)
4200        assert_eq!(header[4] as u64, (4 * 2 + 13) as u64);
4201
4202        // Check that the bytes after the header can be interpreted as the correct values
4203        let mut cur_offset = header_length;
4204        let i8_bytes = &buf[cur_offset..cur_offset + size_of::<i8>()];
4205        cur_offset += size_of::<i8>();
4206        let f64_bytes = &buf[cur_offset..cur_offset + size_of::<f64>()];
4207        cur_offset += size_of::<f64>();
4208        let text_bytes = &buf[cur_offset..cur_offset + text.len()];
4209
4210        let val_int8 = i8::from_be_bytes(i8_bytes.try_into().unwrap());
4211        let val_float = f64::from_be_bytes(f64_bytes.try_into().unwrap());
4212        let val_text = String::from_utf8(text_bytes.to_vec()).unwrap();
4213
4214        assert_eq!(val_int8, 42);
4215        assert_eq!(val_float, 3.15);
4216        assert_eq!(val_text, "test");
4217
4218        // Check that buffer length is correct
4219        assert_eq!(
4220            buf.len(),
4221            header_length + size_of::<i8>() + size_of::<f64>() + text.len()
4222        );
4223    }
4224
4225    /// Before the Numeric refactor, ValueRef had separate Float(f64) and Integer(i64)
4226    /// variants. A raw f64::NAN could be stored in Float, and comparing two NaN floats
4227    /// via partial_cmp returned None. The .unwrap() in Ord::cmp and
4228    /// compare_immutable_single would then panic.
4229    ///
4230    /// Now Numeric::Float wraps NonNan, which rejects NaN at construction time.
4231    /// This makes it impossible to represent NaN in a ValueRef, so partial_cmp
4232    /// is total and can never return None for any representable value.
4233    #[test]
4234    fn test_valueref_partial_cmp_no_panic_on_nan() {
4235        use crate::numeric::nonnan::NonNan;
4236
4237        // NonNan::new rejects NaN — this is the type-level guarantee that
4238        // prevents the old panic. No ValueRef::Float(NAN) can be constructed.
4239        assert!(NonNan::new(f64::NAN).is_none());
4240
4241        // from_f64(NAN) falls back to Null instead of storing a NaN float.
4242        assert_eq!(ValueRef::from_f64(f64::NAN), ValueRef::Null);
4243
4244        // Exercise every representable float edge case through partial_cmp,
4245        // Ord::cmp, and compare_immutable_single — none of these can panic now.
4246        let values: Vec<ValueRef> = vec![
4247            ValueRef::Null,
4248            ValueRef::from_i64(0),
4249            ValueRef::from_i64(-1),
4250            ValueRef::from_i64(i64::MAX),
4251            ValueRef::from_i64(i64::MIN),
4252            ValueRef::from_f64(0.0),
4253            ValueRef::from_f64(-0.0),
4254            ValueRef::from_f64(1.5),
4255            ValueRef::from_f64(-1.5),
4256            ValueRef::from_f64(f64::MAX),
4257            ValueRef::from_f64(f64::MIN),
4258            ValueRef::from_f64(f64::MIN_POSITIVE),
4259            ValueRef::from_f64(f64::INFINITY),
4260            ValueRef::from_f64(f64::NEG_INFINITY),
4261            ValueRef::from_f64(f64::NAN), // becomes Null
4262            ValueRef::Text(TextRef::new("hello", TextSubtype::Text)),
4263            ValueRef::Text(TextRef::new("", TextSubtype::Text)),
4264            ValueRef::Blob(&[1, 2, 3]),
4265            ValueRef::Blob(&[]),
4266        ];
4267
4268        // partial_cmp must return Some for every pair — the old code panicked
4269        // here when either side was Float(NAN).
4270        for (i, a) in values.iter().enumerate() {
4271            for (j, b) in values.iter().enumerate() {
4272                let result = a.partial_cmp(b);
4273                assert!(
4274                    result.is_some(),
4275                    "partial_cmp returned None for values[{i}]={a:?} vs values[{j}]={b:?}"
4276                );
4277                // Ord::cmp (which previously called partial_cmp().unwrap()) must agree.
4278                assert_eq!(result.unwrap(), a.cmp(b));
4279            }
4280        }
4281
4282        // compare_immutable_single is where the unwrap panic originally surfaced.
4283        for a in &values {
4284            for b in &values {
4285                let _ = compare_immutable_single(*a, *b, CollationSeq::Binary);
4286            }
4287        }
4288
4289        // Antisymmetry holds for all pairs.
4290        for a in &values {
4291            for b in &values {
4292                let ab = a.cmp(b);
4293                let ba = b.cmp(a);
4294                assert_eq!(ab, ba.reverse(), "antisymmetry failed for {a:?} vs {b:?}");
4295            }
4296        }
4297    }
4298
4299    #[test]
4300    fn test_column_count_matches_values_written() {
4301        // Test with different numbers of values
4302        for num_values in 1..=10 {
4303            let values: Vec<Value> = (0..num_values)
4304                .map(|i| Value::from_i64(i as i64))
4305                .try_collect()
4306                .unwrap();
4307
4308            let record = ImmutableRecord::from_values(&values, values.len()).unwrap();
4309            let cnt = record.column_count();
4310            assert_eq!(
4311                cnt, num_values,
4312                "column_count should be {num_values}, not {cnt}"
4313            );
4314        }
4315    }
4316}