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