Skip to main content

radixdb_core/
row.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Row type for RadixDB - a collection of column values
16//!
17//! # Storage Design
18//!
19//! Row uses a simple 2-variant storage model:
20//! - `Shared(CompactArc<[Value]>)`: O(1) clone, for storage reads and sharing
21//! - `Owned(CompactVec<Value>)`: Mutable, for intermediate results
22//!
23//! This design avoids per-value Arc overhead while enabling:
24//! - Row-level sharing between arena, version store, transaction store
25//! - String-level sharing via `SmartString::Shared(Arc<str>)`
26//! - Zero-copy JOINs via RowRef::Composite/DirectBuildComposite (see operator.rs)
27
28use std::fmt;
29use std::ops::Index;
30
31use crate::{CompactArc, CompactVec, DataType, Error, LogicalTypeRef, Result, Value};
32
33/// Read-only column metadata required by row construction and validation.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct RowColumnRef<'a> {
36    pub name: &'a str,
37    pub data_type: DataType,
38    pub logical_type: LogicalTypeRef,
39    pub nullable: bool,
40}
41
42impl<'a> RowColumnRef<'a> {
43    pub const fn new(name: &'a str, data_type: DataType, nullable: bool) -> Self {
44        Self {
45            name,
46            data_type,
47            logical_type: LogicalTypeRef::Builtin(data_type),
48            nullable,
49        }
50    }
51
52    pub const fn with_logical_type(mut self, logical_type: LogicalTypeRef) -> Self {
53        self.logical_type = logical_type;
54        self
55    }
56}
57
58/// Minimal schema view consumed by the canonical row owner.
59///
60/// Every index below [`RowSchema::row_column_count`] must resolve to a column.
61pub trait RowSchema {
62    fn row_column_count(&self) -> usize;
63    fn row_column(&self, index: usize) -> Option<RowColumnRef<'_>>;
64}
65
66/// Internal storage for Row - simple 2-variant design
67///
68/// - `Shared`: Arc-wrapped for O(1) clone (storage reads, sharing)
69/// - `Owned`: Direct values for mutations and intermediate results
70///
71/// Both variants are 16 bytes for optimal move performance.
72#[derive(Debug, Clone)]
73enum RowStorage {
74    /// Shared storage - O(1) clone, immutable (checked first for read-heavy workloads)
75    Shared(CompactArc<[Value]>),
76    /// Owned storage - mutable, for intermediate results
77    Owned(CompactVec<Value>),
78}
79
80impl Default for RowStorage {
81    fn default() -> Self {
82        RowStorage::Owned(CompactVec::new())
83    }
84}
85
86impl PartialEq for RowStorage {
87    #[inline]
88    fn eq(&self, other: &Self) -> bool {
89        match (self, other) {
90            (RowStorage::Shared(a), RowStorage::Shared(b)) => {
91                // Fast path: same Arc pointer
92                CompactArc::ptr_eq(a, b) || a.as_ref() == b.as_ref()
93            }
94            (RowStorage::Owned(a), RowStorage::Owned(b)) => a.as_slice() == b.as_slice(),
95            // Mixed storage types - compare by value
96            (RowStorage::Shared(a), RowStorage::Owned(b)) => a.as_ref() == b.as_slice(),
97            (RowStorage::Owned(a), RowStorage::Shared(b)) => a.as_slice() == b.as_ref(),
98        }
99    }
100}
101
102impl RowStorage {
103    /// Get a value by index
104    #[inline(always)]
105    fn get(&self, index: usize) -> Option<&Value> {
106        match self {
107            RowStorage::Shared(arc) => arc.get(index),
108            RowStorage::Owned(vec) => vec.get(index),
109        }
110    }
111
112    #[inline(always)]
113    fn len(&self) -> usize {
114        match self {
115            RowStorage::Shared(arc) => arc.len(),
116            RowStorage::Owned(vec) => vec.len(),
117        }
118    }
119
120    #[inline]
121    fn is_empty(&self) -> bool {
122        self.len() == 0
123    }
124
125    /// Get mutable access to owned storage, converting if necessary (copy-on-write)
126    #[inline]
127    fn make_mut(&mut self) -> &mut CompactVec<Value> {
128        match self {
129            RowStorage::Owned(vec) => vec,
130            RowStorage::Shared(arc) => {
131                // Copy-on-write: convert shared to owned
132                // Use extend_clone directly instead of .cloned().collect() to avoid
133                // the Cloned iterator adapter overhead
134                let len = arc.len();
135                let mut vec = CompactVec::with_capacity(len);
136                vec.extend_clone(arc);
137                *self = RowStorage::Owned(vec);
138                match self {
139                    RowStorage::Owned(vec) => vec,
140                    _ => unreachable!(),
141                }
142            }
143        }
144    }
145
146    /// Convert to owned Vec<Value>, consuming self
147    #[inline]
148    fn into_vec(self) -> Vec<Value> {
149        match self {
150            RowStorage::Owned(vec) => vec.into_vec(),
151            RowStorage::Shared(arc) => arc.iter().cloned().collect(),
152        }
153    }
154}
155
156/// A database row containing column values
157///
158/// Row provides methods for accessing and manipulating column values
159/// while maintaining type safety and consistency with the schema.
160///
161/// # Performance
162///
163/// - `Shared` storage: O(1) clone (just Arc increment)
164/// - `Owned` storage: O(n) clone (copies values)
165/// - String values use `SmartString` with internal `Arc<str>` for efficient sharing
166#[derive(Debug, Clone, PartialEq, Default)]
167pub struct Row {
168    storage: RowStorage,
169}
170
171/// Iterator over row values
172pub struct RowIter<'a> {
173    inner: std::slice::Iter<'a, Value>,
174}
175
176impl<'a> Iterator for RowIter<'a> {
177    type Item = &'a Value;
178
179    #[inline]
180    fn next(&mut self) -> Option<Self::Item> {
181        self.inner.next()
182    }
183
184    #[inline]
185    fn size_hint(&self) -> (usize, Option<usize>) {
186        self.inner.size_hint()
187    }
188}
189
190impl<'a> ExactSizeIterator for RowIter<'a> {
191    fn len(&self) -> usize {
192        self.inner.len()
193    }
194}
195
196impl<'a> DoubleEndedIterator for RowIter<'a> {
197    fn next_back(&mut self) -> Option<Self::Item> {
198        self.inner.next_back()
199    }
200}
201
202/// Mutable iterator over row values
203pub struct RowIterMut<'a> {
204    inner: std::slice::IterMut<'a, Value>,
205}
206
207impl<'a> Iterator for RowIterMut<'a> {
208    type Item = &'a mut Value;
209
210    #[inline]
211    fn next(&mut self) -> Option<Self::Item> {
212        self.inner.next()
213    }
214
215    #[inline]
216    fn size_hint(&self) -> (usize, Option<usize>) {
217        self.inner.size_hint()
218    }
219}
220
221impl<'a> ExactSizeIterator for RowIterMut<'a> {
222    fn len(&self) -> usize {
223        self.inner.len()
224    }
225}
226
227impl Row {
228    /// Create a new empty row
229    #[inline]
230    pub fn new() -> Self {
231        Self {
232            storage: RowStorage::Owned(CompactVec::new()),
233        }
234    }
235
236    /// Create a row with pre-allocated capacity
237    #[inline]
238    pub fn with_capacity(capacity: usize) -> Self {
239        Self {
240            storage: RowStorage::Owned(CompactVec::with_capacity(capacity)),
241        }
242    }
243
244    /// Create a row from a vector of values
245    #[inline]
246    pub fn from_values(values: Vec<Value>) -> Self {
247        Self {
248            storage: RowStorage::Owned(CompactVec::from_vec(values)),
249        }
250    }
251
252    /// Create a row from `CompactVec<Value>`
253    #[inline]
254    pub fn from_compact_vec(values: CompactVec<Value>) -> Self {
255        Self {
256            storage: RowStorage::Owned(values),
257        }
258    }
259
260    /// Create a row from an Arc slice - O(1), no copying
261    #[inline]
262    pub fn from_arc(values: CompactArc<[Value]>) -> Self {
263        Self {
264            storage: RowStorage::Shared(values),
265        }
266    }
267
268    /// Create a row by combining two rows (for JOINs)
269    /// Result uses Owned storage (optimal for intermediate results)
270    #[inline]
271    pub fn from_combined(left: &Row, right: &Row) -> Self {
272        let total_len = left.len() + right.len();
273        let mut values = CompactVec::with_capacity(total_len);
274        // Use extend_clone to avoid Cloned iterator adapter overhead
275        values.extend_clone(left.as_slice());
276        values.extend_clone(right.as_slice());
277        Self {
278            storage: RowStorage::Owned(values),
279        }
280    }
281
282    /// Combine rows: move both (for JOINs) - reuses allocation
283    #[inline]
284    pub fn combine_into_owned(&mut self, left: Row, right: Row) {
285        let total_len = left.len() + right.len();
286        let vec = self.storage.make_mut();
287        vec.clear();
288        vec.reserve(total_len);
289        // Move left values - use extend_clone to avoid Cloned iterator overhead
290        match left.storage {
291            RowStorage::Owned(left_vec) => vec.extend(left_vec),
292            RowStorage::Shared(arc) => vec.extend_clone(&arc),
293        }
294        // Move right values
295        match right.storage {
296            RowStorage::Owned(right_vec) => vec.extend(right_vec),
297            RowStorage::Shared(arc) => vec.extend_clone(&arc),
298        }
299    }
300
301    /// Combine rows: clone left, move right (for JOINs)
302    #[inline]
303    pub fn from_combined_clone_move(left: &Row, right: Row) -> Self {
304        let total_len = left.len() + right.len();
305        let mut values = CompactVec::with_capacity(total_len);
306        // Use extend_clone to avoid Cloned iterator adapter overhead
307        values.extend_clone(left.as_slice());
308        match right.storage {
309            RowStorage::Owned(right_vec) => values.extend(right_vec),
310            RowStorage::Shared(arc) => values.extend_clone(&arc),
311        }
312        Self {
313            storage: RowStorage::Owned(values),
314        }
315    }
316
317    /// Combine two owned rows (for JOINs) - moves values without cloning
318    #[inline]
319    pub fn from_combined_owned(left: Row, right: Row) -> Self {
320        // Fast path: both Owned
321        match (left.storage, right.storage) {
322            (RowStorage::Owned(mut left_vec), RowStorage::Owned(right_vec)) => {
323                left_vec.reserve(right_vec.len());
324                left_vec.extend(right_vec);
325                Self {
326                    storage: RowStorage::Owned(left_vec),
327                }
328            }
329            (left_storage, right_storage) => {
330                let left_len = left_storage.len();
331                let right_len = right_storage.len();
332                let mut values = CompactVec::with_capacity(left_len + right_len);
333                // Use extend_clone to avoid Cloned iterator adapter overhead
334                match left_storage {
335                    RowStorage::Owned(v) => values.extend(v),
336                    RowStorage::Shared(a) => values.extend_clone(&a),
337                }
338                match right_storage {
339                    RowStorage::Owned(v) => values.extend(v),
340                    RowStorage::Shared(a) => values.extend_clone(&a),
341                }
342                Self {
343                    storage: RowStorage::Owned(values),
344                }
345            }
346        }
347    }
348
349    /// Create a row with null values for a given schema
350    #[inline]
351    pub fn null_row<S: RowSchema + ?Sized>(schema: &S) -> Self {
352        let values: CompactVec<Value> = (0..schema.row_column_count())
353            .map(|index| {
354                let column = schema
355                    .row_column(index)
356                    .expect("RowSchema must resolve every declared column index");
357                Value::null(column.data_type)
358            })
359            .collect();
360        Self {
361            storage: RowStorage::Owned(values),
362        }
363    }
364
365    /// Get the number of values in the row
366    #[inline(always)]
367    pub fn len(&self) -> usize {
368        self.storage.len()
369    }
370
371    /// Check if the row is empty
372    #[inline]
373    pub fn is_empty(&self) -> bool {
374        self.storage.is_empty()
375    }
376
377    /// Get a value by index
378    #[inline(always)]
379    pub fn get(&self, index: usize) -> Option<&Value> {
380        self.storage.get(index)
381    }
382
383    /// Get a mutable value by index (triggers copy-on-write if shared)
384    #[inline]
385    pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
386        self.storage.make_mut().get_mut(index)
387    }
388
389    /// Set a value at the given index (triggers copy-on-write if shared)
390    pub fn set(&mut self, index: usize, value: Value) -> Result<()> {
391        let vec = self.storage.make_mut();
392        if index >= vec.len() {
393            return Err(Error::Internal {
394                message: format!("row index {} out of bounds (len={})", index, vec.len()),
395            });
396        }
397        vec[index] = value;
398        Ok(())
399    }
400
401    /// Push a value to the end of the row
402    #[inline]
403    pub fn push(&mut self, value: Value) {
404        self.storage.make_mut().push(value);
405    }
406
407    /// Pop a value from the end of the row
408    #[inline]
409    pub fn pop(&mut self) -> Option<Value> {
410        self.storage.make_mut().pop()
411    }
412
413    /// Remove one value by physical column position.
414    ///
415    /// This is crate-internal because arbitrary callers must not mutate a row's
416    /// schema identity. Schema-evolution code uses it while holding the DDL
417    /// publication fence to rewrite every hot MVCC version atomically.
418    #[inline]
419    #[doc(hidden)]
420    pub fn remove_column(&mut self, index: usize) -> Option<Value> {
421        (index < self.len()).then(|| self.storage.make_mut().remove(index))
422    }
423
424    /// Truncate the row to a specific length
425    #[inline]
426    pub fn truncate(&mut self, len: usize) {
427        self.storage.make_mut().truncate(len);
428    }
429
430    /// Clear the row values while keeping allocated capacity
431    #[inline]
432    pub fn clear(&mut self) {
433        self.storage.make_mut().clear();
434    }
435
436    /// Take the values from this row, returning them in a new Row.
437    /// The original row is cleared but keeps its allocated capacity.
438    #[inline]
439    pub fn take_and_clear(&mut self) -> Row {
440        match &mut self.storage {
441            RowStorage::Owned(vec) => {
442                let cap = vec.capacity();
443                let values = std::mem::replace(vec, CompactVec::with_capacity(cap));
444                Row {
445                    storage: RowStorage::Owned(values),
446                }
447            }
448            RowStorage::Shared(arc) => {
449                let result = Row {
450                    storage: RowStorage::Shared(arc.clone()),
451                };
452                *self = Row::new();
453                result
454            }
455        }
456    }
457
458    /// Reserve capacity for at least `additional` more values
459    #[inline]
460    pub fn reserve(&mut self, additional: usize) {
461        self.storage.make_mut().reserve(additional);
462    }
463
464    /// Extend the row with values from a slice
465    #[inline]
466    pub fn extend_from_slice(&mut self, other: &[Value]) {
467        self.storage.make_mut().extend_clone(other);
468    }
469
470    /// Extend a CompactVec with this row's values, consuming self.
471    ///
472    /// OPTIMIZATION: This avoids the intermediate Vec allocation that would occur
473    /// with `target.extend(row)` which goes through `Row::into_iter()`.
474    /// - Owned storage: directly extends from CompactVec (moves values)
475    /// - Shared storage: clones values from Arc slice
476    #[inline]
477    pub fn extend_into_compact_vec(self, target: &mut CompactVec<Value>) {
478        match self.storage {
479            RowStorage::Owned(vec) => target.extend(vec),
480            RowStorage::Shared(arc) => target.extend_clone(&arc),
481        }
482    }
483
484    /// Get an iterator over the values
485    #[inline(always)]
486    pub fn iter(&self) -> RowIter<'_> {
487        RowIter {
488            inner: match &self.storage {
489                RowStorage::Shared(arc) => arc.iter(),
490                RowStorage::Owned(vec) => vec.iter(),
491            },
492        }
493    }
494
495    /// Get a mutable iterator over the values (triggers copy-on-write if shared)
496    #[inline]
497    pub fn iter_mut(&mut self) -> RowIterMut<'_> {
498        RowIterMut {
499            inner: self.storage.make_mut().iter_mut(),
500        }
501    }
502
503    /// Get the underlying vector of values, consuming the row
504    #[inline]
505    pub fn into_values(self) -> Vec<Value> {
506        self.storage.into_vec()
507    }
508
509    /// Extract the first value, consuming the row
510    #[inline]
511    pub fn take_first_value(self) -> Option<Value> {
512        match self.storage {
513            RowStorage::Owned(mut vec) => {
514                if vec.is_empty() {
515                    None
516                } else {
517                    Some(vec.swap_remove(0))
518                }
519            }
520            RowStorage::Shared(arc) => arc.first().cloned(),
521        }
522    }
523
524    /// Check if storage is shared (Arc-wrapped)
525    #[inline]
526    pub fn is_shared(&self) -> bool {
527        matches!(self.storage, RowStorage::Shared(_))
528    }
529
530    /// Check if storage is owned
531    #[inline]
532    pub fn is_owned(&self) -> bool {
533        matches!(self.storage, RowStorage::Owned(_))
534    }
535
536    /// Convert Row to CompactArc<[Value]>, consuming self
537    /// - Shared: returns the CompactArc directly (O(1))
538    /// - Owned: creates new Arc (O(n))
539    #[inline]
540    pub fn into_arc(self) -> CompactArc<[Value]> {
541        match self.storage {
542            RowStorage::Shared(arc) => arc,
543            // Use from_compact_vec directly - avoids intermediate Vec conversion
544            RowStorage::Owned(vec) => CompactArc::from_compact_vec(vec),
545        }
546    }
547
548    /// Get CompactArc<[Value]> reference if shared, None if owned
549    #[inline]
550    pub fn as_arc(&self) -> Option<&CompactArc<[Value]>> {
551        match &self.storage {
552            RowStorage::Shared(arc) => Some(arc),
553            RowStorage::Owned(_) => None,
554        }
555    }
556
557    /// Get slice of values
558    #[inline]
559    pub fn as_slice(&self) -> &[Value] {
560        match &self.storage {
561            RowStorage::Shared(arc) => arc,
562            RowStorage::Owned(vec) => vec.as_slice(),
563        }
564    }
565
566    /// Extract specific columns by their indices
567    #[inline]
568    pub fn select_columns(&self, indices: &[usize]) -> Result<Row> {
569        self.validate_projection_indices(indices)?;
570        let mut values = CompactVec::with_capacity(indices.len());
571        for &idx in indices {
572            values.push(
573                self.storage
574                    .get(idx)
575                    .expect("projection index validated")
576                    .clone(),
577            );
578        }
579        Ok(Row::from_compact_vec(values))
580    }
581
582    #[inline]
583    fn validate_projection_indices(&self, indices: &[usize]) -> Result<()> {
584        let len = self.len();
585        if let Some(&idx) = indices.iter().find(|&&idx| idx >= len) {
586            return Err(Error::Internal {
587                message: format!("column index {} out of bounds (len={})", idx, len),
588            });
589        }
590        Ok(())
591    }
592
593    /// Take specific columns by their indices, consuming the row
594    /// Detects prefix projections (0, 1, 2, ..., n-1) and truncates in-place.
595    #[inline]
596    pub fn take_columns(self, indices: &[usize]) -> Result<Row> {
597        self.validate_projection_indices(indices)?;
598        // Fast path: check if indices form a prefix (0, 1, 2, ..., n-1)
599        let is_prefix = !indices.is_empty() && indices.iter().enumerate().all(|(i, &idx)| i == idx);
600
601        if is_prefix {
602            match self.storage {
603                RowStorage::Owned(mut vec) => {
604                    vec.truncate(indices.len());
605                    return Ok(Row {
606                        storage: RowStorage::Owned(vec),
607                    });
608                }
609                RowStorage::Shared(ref arc) if indices.len() == arc.len() => {
610                    return Ok(self);
611                }
612                RowStorage::Shared(arc) => {
613                    // Prefix selection from Shared
614                    let values: CompactVec<Value> = arc[..indices.len()].iter().cloned().collect();
615                    return Ok(Row {
616                        storage: RowStorage::Owned(values),
617                    });
618                }
619            }
620        }
621
622        // General case: select specific columns
623        let mut values = CompactVec::with_capacity(indices.len());
624        let slice = self.as_slice();
625        for &idx in indices {
626            values.push(slice[idx].clone());
627        }
628        Ok(Row {
629            storage: RowStorage::Owned(values),
630        })
631    }
632
633    /// Validate the row against a schema
634    pub fn validate<S: RowSchema + ?Sized>(&self, schema: &S) -> Result<()> {
635        let len = self.len();
636        let column_count = schema.row_column_count();
637
638        // Check column count
639        if len != column_count {
640            return Err(Error::table_columns_not_match(column_count, len));
641        }
642
643        // Check each value
644        for (i, value) in self.iter().enumerate() {
645            let col = schema
646                .row_column(i)
647                .expect("RowSchema must resolve every declared column index");
648            // Check nullability
649            if value.is_null() && !col.nullable {
650                return Err(Error::not_null_constraint(col.name));
651            }
652
653            // Check type compatibility (skip for null values)
654            if !value.is_null() {
655                let value_type = value.logical_type();
656                if value_type != col.logical_type {
657                    // Allow some implicit conversions
658                    let compatible = matches!(
659                        (value_type, col.logical_type),
660                        (
661                            LogicalTypeRef::Builtin(DataType::Integer),
662                            LogicalTypeRef::Builtin(DataType::Float)
663                        ) | (
664                            LogicalTypeRef::Builtin(DataType::Float),
665                            LogicalTypeRef::Builtin(DataType::Integer)
666                        )
667                    );
668                    if !compatible {
669                        return Err(Error::type_conversion(
670                            format!("column {} at index {}: {:?}", col.name, i, value_type),
671                            format!("{:?}", col.logical_type),
672                        ));
673                    }
674                }
675            }
676        }
677
678        Ok(())
679    }
680
681    /// Clone the row, selecting only the specified column indices
682    #[inline]
683    pub fn clone_subset(&self, indices: &[usize]) -> Result<Row> {
684        self.select_columns(indices)
685    }
686
687    /// Concatenate two rows
688    pub fn concat(&self, other: &Row) -> Row {
689        let total_len = self.len() + other.len();
690        let mut values = CompactVec::with_capacity(total_len);
691        values.extend(self.iter().cloned());
692        values.extend(other.iter().cloned());
693        Row::from_compact_vec(values)
694    }
695
696    /// Create a row by repeating a value
697    pub fn repeat(value: Value, count: usize) -> Row {
698        let mut values = CompactVec::with_capacity(count);
699        for _ in 0..count {
700            values.push(value.clone());
701        }
702        Row::from_compact_vec(values)
703    }
704
705    // === Compatibility methods for gradual migration ===
706    // These methods maintain API compatibility with code expecting CompactArc
707
708    /// Alias for is_owned (backwards compatibility)
709    #[inline]
710    pub fn is_inline(&self) -> bool {
711        self.is_owned()
712    }
713
714    /// Clear and use as inline storage (backwards compatibility)
715    #[inline]
716    pub fn clear_inline(&mut self) {
717        self.clear();
718    }
719
720    /// Push to inline storage (backwards compatibility)
721    #[inline]
722    pub fn push_inline(&mut self, value: Value) {
723        self.push(value);
724    }
725
726    /// Reserve inline capacity (backwards compatibility)
727    #[inline]
728    pub fn reserve_inline(&mut self, capacity: usize) {
729        let vec = self.storage.make_mut();
730        if vec.capacity() < capacity {
731            vec.reserve(capacity - vec.len());
732        }
733    }
734}
735
736// Implement Index for convenient access
737impl Index<usize> for Row {
738    type Output = Value;
739
740    #[inline]
741    fn index(&self, index: usize) -> &Self::Output {
742        self.storage.get(index).expect("row index out of bounds")
743    }
744}
745
746// Implement FromIterator for collecting values into a row
747impl FromIterator<Value> for Row {
748    fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
749        Row::from_compact_vec(iter.into_iter().collect())
750    }
751}
752
753// Implement IntoIterator for consuming iteration
754impl IntoIterator for Row {
755    type Item = Value;
756    type IntoIter = std::vec::IntoIter<Value>;
757
758    fn into_iter(self) -> Self::IntoIter {
759        self.storage.into_vec().into_iter()
760    }
761}
762
763impl<'a> IntoIterator for &'a Row {
764    type Item = &'a Value;
765    type IntoIter = RowIter<'a>;
766
767    fn into_iter(self) -> Self::IntoIter {
768        self.iter()
769    }
770}
771
772impl From<Vec<Value>> for Row {
773    fn from(values: Vec<Value>) -> Self {
774        Row::from_values(values)
775    }
776}
777
778impl From<CompactArc<[Value]>> for Row {
779    fn from(values: CompactArc<[Value]>) -> Self {
780        Row::from_arc(values)
781    }
782}
783
784impl fmt::Display for Row {
785    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786        write!(f, "(")?;
787        for (i, value) in self.iter().enumerate() {
788            if i > 0 {
789                write!(f, ", ")?;
790            }
791            write!(f, "{}", value)?;
792        }
793        write!(f, ")")
794    }
795}
796
797/// Macro for creating rows conveniently
798#[macro_export]
799macro_rules! row {
800    () => {
801        $crate::Row::new()
802    };
803    ($($value:expr),+ $(,)?) => {
804        $crate::Row::from_values(vec![$($crate::Value::from($value)),+])
805    };
806}
807
808#[cfg(test)]
809mod tests {
810    use super::*;
811    use crate::CompactArc;
812
813    struct TestSchema(Vec<(&'static str, DataType, bool)>);
814
815    impl RowSchema for TestSchema {
816        fn row_column_count(&self) -> usize {
817            self.0.len()
818        }
819
820        fn row_column(&self, index: usize) -> Option<RowColumnRef<'_>> {
821            self.0
822                .get(index)
823                .map(|(name, data_type, nullable)| RowColumnRef::new(name, *data_type, *nullable))
824        }
825    }
826
827    fn create_test_schema() -> TestSchema {
828        TestSchema(vec![
829            ("id", DataType::Integer, false),
830            ("name", DataType::Text, false),
831            ("email", DataType::Text, true),
832        ])
833    }
834
835    #[test]
836    fn test_row_creation() {
837        let row = Row::new();
838        assert!(row.is_empty());
839        assert_eq!(row.len(), 0);
840
841        let row = Row::with_capacity(10);
842        assert!(row.is_empty());
843    }
844
845    #[test]
846    fn test_row_from_values() {
847        let values = vec![
848            Value::integer(1),
849            Value::text("hello"),
850            Value::null(DataType::Text),
851        ];
852        let row = Row::from_values(values);
853        assert_eq!(row.len(), 3);
854        assert!(row.is_owned());
855    }
856
857    #[test]
858    fn test_row_from_arc() {
859        let values: CompactArc<[Value]> =
860            CompactArc::from(vec![Value::integer(1), Value::text("hello")]);
861        let row = Row::from_arc(values);
862        assert_eq!(row.len(), 2);
863        assert!(row.is_shared());
864
865        // Clone should be O(1) - just Arc increment
866        let row2 = row.clone();
867        assert_eq!(row2.len(), 2);
868        assert_eq!(row, row2);
869        assert!(row2.is_shared());
870    }
871
872    #[test]
873    fn test_row_push_pop() {
874        let mut row = Row::new();
875        row.push(Value::integer(1));
876        row.push(Value::text("hello"));
877
878        assert_eq!(row.len(), 2);
879
880        let popped = row.pop();
881        assert_eq!(popped, Some(Value::text("hello")));
882        assert_eq!(row.len(), 1);
883    }
884
885    #[test]
886    fn test_row_copy_on_write() {
887        // Create shared row
888        let values: CompactArc<[Value]> =
889            CompactArc::from(vec![Value::integer(1), Value::text("hello")]);
890        let mut row = Row::from_arc(values);
891        assert!(row.is_shared());
892
893        // Mutation should trigger copy-on-write
894        row.push(Value::integer(2));
895        assert_eq!(row.len(), 3);
896        assert!(row.is_owned()); // Now owned after mutation
897    }
898
899    #[test]
900    fn test_row_get_set() {
901        let mut row = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
902
903        assert_eq!(row.get(0), Some(&Value::integer(1)));
904        assert_eq!(row.get(1), Some(&Value::text("hello")));
905        assert_eq!(row.get(2), None);
906
907        row.set(1, Value::text("world")).unwrap();
908        assert_eq!(row.get(1), Some(&Value::text("world")));
909
910        assert!(row.set(10, Value::integer(0)).is_err());
911    }
912
913    #[test]
914    fn test_row_index() {
915        let row = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
916
917        assert_eq!(row[0], Value::integer(1));
918        assert_eq!(row[1], Value::text("hello"));
919    }
920
921    #[test]
922    fn test_row_iteration() {
923        let row = Row::from_values(vec![
924            Value::integer(1),
925            Value::integer(2),
926            Value::integer(3),
927        ]);
928
929        let sum: i64 = row.iter().filter_map(|v| v.as_int64()).sum();
930        assert_eq!(sum, 6);
931    }
932
933    #[test]
934    fn test_row_select_columns() {
935        let row = Row::from_values(vec![
936            Value::integer(1),
937            Value::text("hello"),
938            Value::float(3.5),
939            Value::boolean(true),
940        ]);
941
942        let selected = row.select_columns(&[0, 2]).unwrap();
943        assert_eq!(selected.len(), 2);
944        assert_eq!(selected[0], Value::integer(1));
945        assert_eq!(selected[1], Value::float(3.5));
946
947        assert!(row.select_columns(&[0, 10]).is_err());
948    }
949
950    #[test]
951    fn test_row_validate() {
952        let schema = create_test_schema();
953
954        // Valid row
955        let row = Row::from_values(vec![
956            Value::integer(1),
957            Value::text("Alice"),
958            Value::null(DataType::Text),
959        ]);
960        assert!(row.validate(&schema).is_ok());
961
962        // Wrong column count
963        let row = Row::from_values(vec![Value::integer(1)]);
964        assert!(row.validate(&schema).is_err());
965
966        // Not null constraint violation
967        let row = Row::from_values(vec![
968            Value::integer(1),
969            Value::null(DataType::Text), // name is not nullable
970            Value::null(DataType::Text),
971        ]);
972        let err = row.validate(&schema).unwrap_err();
973        assert!(matches!(err, Error::NotNullConstraint { .. }));
974    }
975
976    #[test]
977    fn test_row_null_row() {
978        let schema = create_test_schema();
979        let row = Row::null_row(&schema);
980
981        assert_eq!(row.len(), 3);
982        assert!(row[0].is_null());
983        assert!(row[1].is_null());
984        assert!(row[2].is_null());
985    }
986
987    #[test]
988    fn test_row_concat() {
989        let row1 = Row::from_values(vec![Value::integer(1), Value::integer(2)]);
990        let row2 = Row::from_values(vec![Value::integer(3), Value::integer(4)]);
991
992        let combined = row1.concat(&row2);
993        assert_eq!(combined.len(), 4);
994        assert_eq!(combined[0], Value::integer(1));
995        assert_eq!(combined[3], Value::integer(4));
996    }
997
998    #[test]
999    fn test_row_repeat() {
1000        let row = Row::repeat(Value::integer(0), 5);
1001        assert_eq!(row.len(), 5);
1002        for v in row.iter() {
1003            assert_eq!(*v, Value::integer(0));
1004        }
1005    }
1006
1007    #[test]
1008    fn test_row_from_iterator() {
1009        let row: Row = vec![Value::integer(1), Value::integer(2), Value::integer(3)]
1010            .into_iter()
1011            .collect();
1012        assert_eq!(row.len(), 3);
1013    }
1014
1015    #[test]
1016    fn test_row_display() {
1017        let row = Row::from_values(vec![
1018            Value::integer(1),
1019            Value::text("hello"),
1020            Value::null(DataType::Text),
1021        ]);
1022        assert_eq!(row.to_string(), "(1, hello, NULL)");
1023
1024        let empty = Row::new();
1025        assert_eq!(empty.to_string(), "()");
1026    }
1027
1028    #[test]
1029    fn test_row_clone_subset() {
1030        let row = Row::from_values(vec![
1031            Value::integer(1),
1032            Value::text("hello"),
1033            Value::float(3.5),
1034        ]);
1035
1036        let subset = row.clone_subset(&[2, 0]).unwrap();
1037        assert_eq!(subset.len(), 2);
1038        assert_eq!(subset[0], Value::float(3.5));
1039        assert_eq!(subset[1], Value::integer(1));
1040    }
1041
1042    #[test]
1043    fn test_row_projection_helpers_reject_invalid_indices_consistently() {
1044        let row = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1045        let invalid = [0, 2];
1046
1047        assert!(row.select_columns(&invalid).is_err());
1048        assert!(row.clone().take_columns(&invalid).is_err());
1049        assert!(row.clone_subset(&invalid).is_err());
1050    }
1051
1052    #[test]
1053    fn test_row_equality() {
1054        let row1 = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1055        let row2 = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1056        let row3 = Row::from_values(vec![Value::integer(1), Value::text("world")]);
1057
1058        assert_eq!(row1, row2);
1059        assert_ne!(row1, row3);
1060    }
1061
1062    #[test]
1063    fn test_row_into_values() {
1064        let row = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1065        let values = row.into_values();
1066
1067        assert_eq!(values.len(), 2);
1068        assert_eq!(values[0], Value::integer(1));
1069    }
1070
1071    #[test]
1072    fn test_row_into_arc() {
1073        let row = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1074        let arc = row.into_arc();
1075        assert_eq!(arc.len(), 2);
1076
1077        // From shared - should be O(1)
1078        let row2 = Row::from_arc(CompactArc::clone(&arc));
1079        let arc2 = row2.into_arc();
1080        assert!(CompactArc::ptr_eq(&arc, &arc2));
1081    }
1082
1083    #[test]
1084    fn test_row_combined() {
1085        let left = Row::from_values(vec![Value::integer(1), Value::integer(2)]);
1086        let right = Row::from_values(vec![Value::integer(3), Value::integer(4)]);
1087
1088        let combined = Row::from_combined(&left, &right);
1089        assert_eq!(combined.len(), 4);
1090        assert_eq!(combined[0], Value::integer(1));
1091        assert_eq!(combined[3], Value::integer(4));
1092    }
1093
1094    #[test]
1095    fn test_shared_owned_equality() {
1096        let owned = Row::from_values(vec![Value::integer(1), Value::text("hello")]);
1097        let shared = Row::from_arc(CompactArc::from(vec![
1098            Value::integer(1),
1099            Value::text("hello"),
1100        ]));
1101
1102        assert_eq!(owned, shared);
1103    }
1104}