@@ -50,8 +50,14 @@ use crate::rules::RULES;
5050
5151vtable ! ( Sequence ) ;
5252
53- #[ derive( Clone , prost :: Message ) ]
53+ #[ derive( Debug , Clone , Copy ) ]
5454pub struct SequenceMetadata {
55+ base : PValue ,
56+ multiplier : PValue ,
57+ }
58+
59+ #[ derive( Clone , prost:: Message ) ]
60+ pub struct ProstSequenceMetadata {
5561 #[ prost( message, tag = "1" ) ]
5662 base : Option < vortex_proto:: scalar:: ScalarValue > ,
5763 #[ prost( message, tag = "2" ) ]
@@ -78,13 +84,13 @@ pub struct SequenceArray {
7884}
7985
8086impl SequenceArray {
81- pub fn typed_new < T : NativePType + Into < PValue > > (
87+ pub fn try_new_typed < T : NativePType + Into < PValue > > (
8288 base : T ,
8389 multiplier : T ,
8490 nullability : Nullability ,
8591 length : usize ,
8692 ) -> VortexResult < Self > {
87- Self :: new (
93+ Self :: try_new (
8894 base. into ( ) ,
8995 multiplier. into ( ) ,
9096 T :: PTYPE ,
@@ -94,7 +100,7 @@ impl SequenceArray {
94100 }
95101
96102 /// Constructs a sequence array using two integer values (with the same ptype).
97- pub fn new (
103+ pub fn try_new (
98104 base : PValue ,
99105 multiplier : PValue ,
100106 ptype : PType ,
@@ -111,16 +117,23 @@ impl SequenceArray {
111117 ) )
112118 } ) ?;
113119
114- Ok ( Self :: unchecked_new (
115- base,
116- multiplier,
117- ptype,
118- nullability,
119- length,
120- ) )
121- }
122-
123- pub ( crate ) fn unchecked_new (
120+ // SAFETY: we just validated that `ptype` is an integer and that the final
121+ // element is representable via `try_last`.
122+ Ok ( unsafe { Self :: new_unchecked ( base, multiplier, ptype, nullability, length) } )
123+ }
124+
125+ /// Constructs a [`SequenceArray`] without validating that the `ptype` is an integer
126+ /// type or that the final element is representable.
127+ ///
128+ /// # Safety
129+ ///
130+ /// The caller must ensure that:
131+ /// - `ptype` is an integer type (i.e., `ptype.is_int()` returns `true`).
132+ /// - `base + (length - 1) * multiplier` does not overflow the range of `ptype`.
133+ ///
134+ /// Violating the first invariant will cause a panic. Violating the second will
135+ /// cause silent wraparound when materializing elements, producing incorrect values.
136+ pub ( crate ) unsafe fn new_unchecked (
124137 base : PValue ,
125138 multiplier : PValue ,
126139 ptype : PType ,
@@ -226,7 +239,7 @@ impl SequenceArray {
226239impl VTable for SequenceVTable {
227240 type Array = SequenceArray ;
228241
229- type Metadata = ProstMetadata < SequenceMetadata > ;
242+ type Metadata = SequenceMetadata ;
230243 type OperationsVTable = Self ;
231244 type ValidityVTable = Self ;
232245
@@ -289,40 +302,37 @@ impl VTable for SequenceVTable {
289302 }
290303
291304 fn metadata ( array : & SequenceArray ) -> VortexResult < Self :: Metadata > {
292- Ok ( ProstMetadata ( SequenceMetadata {
293- base : Some ( ( & array. base ( ) ) . into ( ) ) ,
294- multiplier : Some ( ( & array. multiplier ( ) ) . into ( ) ) ,
295- } ) )
305+ Ok ( SequenceMetadata {
306+ base : array. base ( ) ,
307+ multiplier : array. multiplier ( ) ,
308+ } )
296309 }
297310
298311 fn serialize ( metadata : Self :: Metadata ) -> VortexResult < Option < Vec < u8 > > > {
299- Ok ( Some ( metadata. serialize ( ) ) )
312+ let prost = ProstMetadata ( ProstSequenceMetadata {
313+ base : Some ( ( & metadata. base ) . into ( ) ) ,
314+ multiplier : Some ( ( & metadata. multiplier ) . into ( ) ) ,
315+ } ) ;
316+
317+ Ok ( Some ( prost. serialize ( ) ) )
300318 }
301319
302320 fn deserialize (
303321 bytes : & [ u8 ] ,
304- _dtype : & DType ,
322+ dtype : & DType ,
305323 _len : usize ,
306324 _buffers : & [ BufferHandle ] ,
307325 _session : & VortexSession ,
308326 ) -> VortexResult < Self :: Metadata > {
309- Ok ( ProstMetadata (
310- <ProstMetadata < SequenceMetadata > as DeserializeMetadata >:: deserialize ( bytes) ?,
311- ) )
312- }
327+ let prost = ProstMetadata (
328+ <ProstMetadata < ProstSequenceMetadata > as DeserializeMetadata >:: deserialize ( bytes) ?,
329+ ) ;
313330
314- fn build (
315- dtype : & DType ,
316- len : usize ,
317- metadata : & Self :: Metadata ,
318- _buffers : & [ BufferHandle ] ,
319- _children : & dyn ArrayChildren ,
320- ) -> VortexResult < SequenceArray > {
321331 let ptype = dtype. as_ptype ( ) ;
322332
323- // We go via scalar to cast the scalar values into the correct PType
333+ // We go via Scalar to validate that the value is valid for the ptype.
324334 let base = Scalar :: from_proto_value (
325- metadata
335+ prost
326336 . 0
327337 . base
328338 . as_ref ( )
@@ -331,10 +341,10 @@ impl VTable for SequenceVTable {
331341 ) ?
332342 . as_primitive ( )
333343 . pvalue ( )
334- . vortex_expect ( "non-nullable primitive" ) ;
344+ . vortex_expect ( "sequence array base should be a non-nullable primitive" ) ;
335345
336346 let multiplier = Scalar :: from_proto_value (
337- metadata
347+ prost
338348 . 0
339349 . multiplier
340350 . as_ref ( )
@@ -343,15 +353,25 @@ impl VTable for SequenceVTable {
343353 ) ?
344354 . as_primitive ( )
345355 . pvalue ( )
346- . vortex_expect ( "non-nullable primitive" ) ;
356+ . vortex_expect ( "sequence array multiplier should be a non-nullable primitive" ) ;
347357
348- Ok ( SequenceArray :: unchecked_new (
349- base,
350- multiplier,
351- ptype,
358+ Ok ( SequenceMetadata { base, multiplier } )
359+ }
360+
361+ fn build (
362+ dtype : & DType ,
363+ len : usize ,
364+ metadata : & Self :: Metadata ,
365+ _buffers : & [ BufferHandle ] ,
366+ _children : & dyn ArrayChildren ,
367+ ) -> VortexResult < SequenceArray > {
368+ SequenceArray :: try_new (
369+ metadata. base ,
370+ metadata. multiplier ,
371+ dtype. as_ptype ( ) ,
352372 dtype. nullability ( ) ,
353373 len,
354- ) )
374+ )
355375 }
356376
357377 fn with_children ( _array : & mut Self :: Array , children : Vec < ArrayRef > ) -> VortexResult < ( ) > {
@@ -433,7 +453,7 @@ mod tests {
433453
434454 #[ test]
435455 fn test_sequence_canonical ( ) {
436- let arr = SequenceArray :: typed_new ( 2i64 , 3 , Nullability :: NonNullable , 4 ) . unwrap ( ) ;
456+ let arr = SequenceArray :: try_new_typed ( 2i64 , 3 , Nullability :: NonNullable , 4 ) . unwrap ( ) ;
437457
438458 let canon = PrimitiveArray :: from_iter ( ( 0 ..4 ) . map ( |i| 2i64 + i * 3 ) ) ;
439459
@@ -442,7 +462,7 @@ mod tests {
442462
443463 #[ test]
444464 fn test_sequence_slice_canonical ( ) {
445- let arr = SequenceArray :: typed_new ( 2i64 , 3 , Nullability :: NonNullable , 4 )
465+ let arr = SequenceArray :: try_new_typed ( 2i64 , 3 , Nullability :: NonNullable , 4 )
446466 . unwrap ( )
447467 . slice ( 2 ..3 )
448468 . unwrap ( ) ;
@@ -454,7 +474,7 @@ mod tests {
454474
455475 #[ test]
456476 fn test_sequence_scalar_at ( ) {
457- let scalar = SequenceArray :: typed_new ( 2i64 , 3 , Nullability :: NonNullable , 4 )
477+ let scalar = SequenceArray :: try_new_typed ( 2i64 , 3 , Nullability :: NonNullable , 4 )
458478 . unwrap ( )
459479 . scalar_at ( 2 )
460480 . unwrap ( ) ;
@@ -467,19 +487,19 @@ mod tests {
467487
468488 #[ test]
469489 fn test_sequence_min_max ( ) {
470- assert ! ( SequenceArray :: typed_new ( -127i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_ok( ) ) ;
471- assert ! ( SequenceArray :: typed_new ( 126i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_ok( ) ) ;
490+ assert ! ( SequenceArray :: try_new_typed ( -127i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_ok( ) ) ;
491+ assert ! ( SequenceArray :: try_new_typed ( 126i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_ok( ) ) ;
472492 }
473493
474494 #[ test]
475495 fn test_sequence_too_big ( ) {
476- assert ! ( SequenceArray :: typed_new ( 127i8 , 1i8 , Nullability :: NonNullable , 2 ) . is_err( ) ) ;
477- assert ! ( SequenceArray :: typed_new ( -128i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_err( ) ) ;
496+ assert ! ( SequenceArray :: try_new_typed ( 127i8 , 1i8 , Nullability :: NonNullable , 2 ) . is_err( ) ) ;
497+ assert ! ( SequenceArray :: try_new_typed ( -128i8 , -1i8 , Nullability :: NonNullable , 2 ) . is_err( ) ) ;
478498 }
479499
480500 #[ test]
481501 fn positive_multiplier_is_strict_sorted ( ) -> VortexResult < ( ) > {
482- let arr = SequenceArray :: typed_new ( 0i64 , 3 , Nullability :: NonNullable , 4 ) ?;
502+ let arr = SequenceArray :: try_new_typed ( 0i64 , 3 , Nullability :: NonNullable , 4 ) ?;
483503
484504 let is_sorted = arr
485505 . statistics ( )
@@ -495,7 +515,7 @@ mod tests {
495515
496516 #[ test]
497517 fn zero_multiplier_is_sorted_not_strict ( ) -> VortexResult < ( ) > {
498- let arr = SequenceArray :: typed_new ( 5i64 , 0 , Nullability :: NonNullable , 4 ) ?;
518+ let arr = SequenceArray :: try_new_typed ( 5i64 , 0 , Nullability :: NonNullable , 4 ) ?;
499519
500520 let is_sorted = arr
501521 . statistics ( )
@@ -511,7 +531,7 @@ mod tests {
511531
512532 #[ test]
513533 fn negative_multiplier_not_sorted ( ) -> VortexResult < ( ) > {
514- let arr = SequenceArray :: typed_new ( 10i64 , -1 , Nullability :: NonNullable , 4 ) ?;
534+ let arr = SequenceArray :: try_new_typed ( 10i64 , -1 , Nullability :: NonNullable , 4 ) ?;
515535
516536 let is_sorted = arr
517537 . statistics ( )
@@ -530,7 +550,7 @@ mod tests {
530550 #[ test]
531551 fn test_large_multiplier_sorted ( ) -> VortexResult < ( ) > {
532552 let large_multiplier = ( i64:: MAX as u64 ) + 1 ;
533- let arr = SequenceArray :: typed_new ( 0 , large_multiplier, Nullability :: NonNullable , 2 ) ?;
553+ let arr = SequenceArray :: try_new_typed ( 0 , large_multiplier, Nullability :: NonNullable , 2 ) ?;
534554
535555 let is_sorted = arr
536556 . statistics ( )
0 commit comments