1use std::fmt::Display;
5use std::fmt::Formatter;
6use std::hash::Hash;
7use std::hash::Hasher;
8
9use num_traits::AsPrimitive;
10use prost::Message;
11use smallvec::smallvec;
12use vortex_array::Array;
13use vortex_array::ArrayEq;
14use vortex_array::ArrayHash;
15use vortex_array::ArrayId;
16use vortex_array::ArrayParts;
17use vortex_array::ArrayRef;
18use vortex_array::ArrayView;
19use vortex_array::EqMode;
20use vortex_array::ExecutionCtx;
21use vortex_array::ExecutionResult;
22use vortex_array::buffer::BufferHandle;
23use vortex_array::dtype::DType;
24use vortex_array::dtype::NativePType;
25use vortex_array::dtype::Nullability;
26use vortex_array::dtype::Nullability::NonNullable;
27use vortex_array::dtype::PType;
28use vortex_array::expr::stats::Precision as StatPrecision;
29use vortex_array::expr::stats::Stat;
30use vortex_array::match_each_integer_ptype;
31use vortex_array::match_each_pvalue;
32use vortex_array::scalar::PValue;
33use vortex_array::scalar::Scalar;
34use vortex_array::scalar::ScalarValue;
35use vortex_array::serde::ArrayChildren;
36use vortex_array::stats::StatsSet;
37use vortex_array::validity::Validity;
38use vortex_array::vtable::OperationsVTable;
39use vortex_array::vtable::VTable;
40use vortex_array::vtable::ValidityVTable;
41use vortex_error::VortexExpect;
42use vortex_error::VortexResult;
43use vortex_error::vortex_bail;
44use vortex_error::vortex_ensure;
45use vortex_error::vortex_err;
46use vortex_error::vortex_panic;
47use vortex_session::VortexSession;
48use vortex_session::registry::CachedId;
49
50use crate::compress::sequence_decompress;
51use crate::eval;
52use crate::eval::SequenceValue;
53use crate::rules::RULES;
54
55pub type SequenceArray = Array<Sequence>;
57
58#[derive(Clone, prost::Message)]
59pub struct SequenceMetadata {
60 #[prost(message, tag = "1")]
61 base: Option<vortex_proto::scalar::ScalarValue>,
62 #[prost(message, tag = "2")]
63 multiplier: Option<vortex_proto::scalar::ScalarValue>,
64}
65
66pub(super) const SLOT_NAMES: [&str; 0] = [];
67
68#[derive(Clone, Debug)]
73pub struct SequenceData {
74 base: PValue,
75 multiplier: PValue,
76}
77
78impl Display for SequenceData {
79 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80 write!(f, "base: {}, multiplier: {}", self.base, self.multiplier)
81 }
82}
83
84pub struct SequenceDataParts {
85 pub base: PValue,
86 pub multiplier: PValue,
87 pub ptype: PType,
88}
89
90impl SequenceData {
91 pub(crate) fn try_new_typed<T: NativePType + Into<PValue>>(
92 base: T,
93 multiplier: T,
94 nullability: Nullability,
95 length: usize,
96 ) -> VortexResult<Self> {
97 Self::try_new(
98 base.into(),
99 multiplier.into(),
100 T::PTYPE,
101 nullability,
102 length,
103 )
104 }
105
106 pub(crate) fn try_new(
108 base: PValue,
109 multiplier: PValue,
110 ptype: PType,
111 nullability: Nullability,
112 length: usize,
113 ) -> VortexResult<Self> {
114 let dtype = DType::Primitive(ptype, nullability);
115 Self::validate(base, multiplier, &dtype, length)?;
116 let (base, multiplier) = Self::normalize(base, multiplier, ptype)?;
117
118 Ok(unsafe { Self::new_unchecked(base, multiplier) })
119 }
120
121 pub fn validate(
122 base: PValue,
123 multiplier: PValue,
124 dtype: &DType,
125 length: usize,
126 ) -> VortexResult<()> {
127 let DType::Primitive(ptype, _) = dtype else {
128 vortex_bail!("only primitive dtypes are supported in SequenceArray currently");
129 };
130
131 if !ptype.is_int() {
132 vortex_bail!("only integer ptypes are supported in SequenceArray currently")
133 }
134
135 vortex_ensure!(length > 0, "SequenceArray length must be greater than zero");
136
137 Self::narrowed_base(base, *ptype)?;
138 Self::ensure_last_expressible(base, multiplier, *ptype, length)
139 }
140
141 fn ensure_last_expressible(
143 base: PValue,
144 multiplier: PValue,
145 ptype: PType,
146 length: usize,
147 ) -> VortexResult<()> {
148 let steps = (length - 1) as u64;
149 let (ascending, magnitude) = eval::step_parts(multiplier)
150 .ok_or_else(|| vortex_err!("step {multiplier} must be an integer"))?;
151 if steps == 0 || magnitude == 0 {
152 return Ok(());
153 }
154
155 let room = if ptype.is_signed_int() {
157 let base = base.cast::<i64>()?;
158 let max = i64::try_from(ptype.max_value_as_u64())
159 .vortex_expect("a signed ptype's max fits i64");
160 base.abs_diff(if ascending { max } else { -max - 1 })
161 } else {
162 let base = base.cast::<u64>()?;
163 if ascending {
164 ptype.max_value_as_u64() - base
165 } else {
166 base
167 }
168 };
169
170 vortex_ensure!(
171 steps <= room / magnitude,
172 "final value not expressible, base = {base:?}, multiplier = {multiplier:?}, len = {length}"
173 );
174 Ok(())
175 }
176
177 fn multiplier_ptype_from_proto(
179 multiplier: &vortex_proto::scalar::ScalarValue,
180 ) -> VortexResult<PType> {
181 use vortex_proto::scalar::scalar_value::Kind;
182 match multiplier
183 .kind
184 .as_ref()
185 .ok_or_else(|| vortex_err!("multiplier value missing kind"))?
186 {
187 Kind::Int64Value(_) => Ok(PType::I64),
188 Kind::Uint64Value(_) => Ok(PType::U64),
189 _ => vortex_bail!("only integer ptypes are supported in SequenceArray currently"),
190 }
191 }
192
193 fn narrowed_base(base: PValue, ptype: PType) -> VortexResult<PValue> {
194 vortex_ensure!(base.ptype().is_int(), "base {base} must be an integer");
195 match_each_integer_ptype!(ptype, |P| { Ok(PValue::from(base.cast::<P>()?)) })
196 }
197
198 fn normalize(base: PValue, multiplier: PValue, ptype: PType) -> VortexResult<(PValue, PValue)> {
200 let base = Self::narrowed_base(base, ptype)?;
201
202 let multiplier = match_each_pvalue!(
204 multiplier,
205 uint: |v| {
206 let v: u64 = v.as_();
207 i64::try_from(v).map(PValue::from).unwrap_or(PValue::U64(v))
208 },
209 int: |v| {
210 let v: i64 = v.as_();
211 PValue::from(v)
212 },
213 float: |v| { vortex_bail!("step {v} must be an integer") }
214 );
215
216 Ok((base, multiplier))
217 }
218
219 pub(crate) unsafe fn new_unchecked(base: PValue, multiplier: PValue) -> Self {
228 Self { base, multiplier }
229 }
230
231 pub fn ptype(&self) -> PType {
233 self.base.ptype()
234 }
235
236 pub fn base(&self) -> PValue {
237 self.base
238 }
239
240 pub fn multiplier(&self) -> PValue {
241 self.multiplier
242 }
243
244 pub(crate) fn wrapping_parts<O: SequenceValue>(&self) -> VortexResult<(O, O)> {
246 eval::wrapping_parts(self.base, self.multiplier).ok_or_else(|| {
247 vortex_err!(
248 "SequenceArray values must be integers, got base {:?} and step {:?}",
249 self.base,
250 self.multiplier
251 )
252 })
253 }
254
255 pub fn wrapping_bits(&self) -> VortexResult<(u64, u64)> {
257 self.wrapping_parts::<u64>()
258 }
259
260 pub fn into_parts(self) -> SequenceDataParts {
261 SequenceDataParts {
262 base: self.base,
263 multiplier: self.multiplier,
264 ptype: self.ptype(),
265 }
266 }
267
268 pub(crate) fn index_value(&self, idx: usize) -> PValue {
269 match_each_integer_ptype!(self.ptype(), |O| {
270 let (base, multiplier) = self
271 .wrapping_parts::<O>()
272 .vortex_expect("sequence values are integers");
273 PValue::from(eval::wrapping_value(base, multiplier, idx))
274 })
275 }
276}
277
278impl ArrayHash for SequenceData {
281 fn array_hash<H: Hasher>(&self, state: &mut H, _accuracy: EqMode) {
282 self.base.hash(state);
283 self.multiplier.hash(state);
284 }
285}
286
287impl ArrayEq for SequenceData {
288 fn array_eq(&self, other: &Self, _accuracy: EqMode) -> bool {
289 self.base.ptype() == other.base.ptype()
290 && self.multiplier.ptype() == other.multiplier.ptype()
291 && self.base == other.base
292 && self.multiplier == other.multiplier
293 }
294}
295
296impl VTable for Sequence {
297 type TypedArrayData = SequenceData;
298
299 type OperationsVTable = Self;
300 type ValidityVTable = Self;
301
302 fn id(&self) -> ArrayId {
303 static ID: CachedId = CachedId::new("vortex.sequence");
304 *ID
305 }
306
307 fn validate(
308 &self,
309 data: &Self::TypedArrayData,
310 dtype: &DType,
311 len: usize,
312 _slots: &[Option<ArrayRef>],
313 ) -> VortexResult<()> {
314 SequenceData::validate(data.base, data.multiplier, dtype, len)
315 }
316
317 fn nbuffers(_array: ArrayView<'_, Self>) -> usize {
318 0
319 }
320
321 fn buffer(_array: ArrayView<'_, Self>, idx: usize) -> BufferHandle {
322 vortex_panic!("SequenceArray buffer index {idx} out of bounds")
323 }
324
325 fn buffer_name(_array: ArrayView<'_, Self>, idx: usize) -> Option<String> {
326 vortex_panic!("SequenceArray buffer_name index {idx} out of bounds")
327 }
328
329 fn with_buffers(
330 &self,
331 array: ArrayView<'_, Self>,
332 buffers: &[BufferHandle],
333 ) -> VortexResult<ArrayParts<Self>> {
334 vortex_array::vtable::with_empty_buffers(self, array, buffers)
335 }
336
337 fn serialize(
338 array: ArrayView<'_, Self>,
339 _session: &VortexSession,
340 ) -> VortexResult<Option<Vec<u8>>> {
341 let metadata = SequenceMetadata {
342 base: Some((&array.base()).into()),
343 multiplier: Some((&array.multiplier()).into()),
344 };
345
346 Ok(Some(metadata.encode_to_vec()))
347 }
348
349 fn deserialize(
350 &self,
351 dtype: &DType,
352 len: usize,
353 metadata: &[u8],
354 buffers: &[BufferHandle],
355 children: &dyn ArrayChildren,
356 session: &VortexSession,
357 ) -> VortexResult<ArrayParts<Self>> {
358 vortex_ensure!(
359 buffers.is_empty(),
360 "SequenceArray expects 0 buffers, got {}",
361 buffers.len()
362 );
363 vortex_ensure!(
364 children.is_empty(),
365 "SequenceArray expects 0 children, got {}",
366 children.len()
367 );
368 let DType::Primitive(output_ptype, _) = dtype else {
369 vortex_bail!(
370 "only primitive dtypes are supported in SequenceArray currently, got {dtype}"
371 );
372 };
373 let metadata = SequenceMetadata::decode(metadata)?;
374
375 let base_metadata = metadata
376 .base
377 .as_ref()
378 .ok_or_else(|| vortex_err!("base required"))?;
379
380 let multiplier_metadata = metadata
381 .multiplier
382 .as_ref()
383 .ok_or_else(|| vortex_err!("multiplier required"))?;
384
385 let base = Scalar::from_proto_value(
387 base_metadata,
388 &DType::Primitive(*output_ptype, NonNullable),
389 session,
390 )?
391 .as_primitive()
392 .pvalue()
393 .vortex_expect("sequence array base should be a non-nullable primitive");
394
395 let multiplier_ptype = SequenceData::multiplier_ptype_from_proto(multiplier_metadata)?;
397 let multiplier = Scalar::from_proto_value(
398 multiplier_metadata,
399 &DType::Primitive(multiplier_ptype, NonNullable),
400 session,
401 )?
402 .as_primitive()
403 .pvalue()
404 .vortex_expect("sequence array multiplier should be a non-nullable primitive");
405
406 let data =
407 SequenceData::try_new(base, multiplier, *output_ptype, dtype.nullability(), len)?;
408 Ok(ArrayParts::new(self.clone(), dtype.clone(), len, data))
409 }
410
411 fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String {
412 SLOT_NAMES[idx].to_string()
413 }
414
415 fn execute(array: Array<Self>, _ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
416 sequence_decompress(&array).map(ExecutionResult::done)
417 }
418
419 fn reduce_parent(
420 array: ArrayView<'_, Self>,
421 parent: &ArrayRef,
422 child_idx: usize,
423 ) -> VortexResult<Option<ArrayRef>> {
424 RULES.evaluate(array, parent, child_idx)
425 }
426}
427
428impl OperationsVTable<Sequence> for Sequence {
429 fn scalar_at(
430 array: ArrayView<'_, Sequence>,
431 index: usize,
432 _ctx: &mut ExecutionCtx,
433 ) -> VortexResult<Scalar> {
434 Scalar::try_new(
435 array.dtype().clone(),
436 Some(ScalarValue::Primitive(array.index_value(index))),
437 )
438 }
439}
440
441impl ValidityVTable<Sequence> for Sequence {
442 fn validity(_array: ArrayView<'_, Sequence>) -> VortexResult<Validity> {
443 Ok(Validity::AllValid)
444 }
445}
446
447#[derive(Clone, Debug)]
448pub struct Sequence;
449
450impl Sequence {
451 fn stats(multiplier: PValue) -> StatsSet {
452 let (is_sorted, is_strict_sorted) = match_each_pvalue!(
455 multiplier,
456 uint: |v| { (true, v > 0) },
457 int: |v| { (v >= 0, v > 0) },
458 float: |_v| { unreachable!("float multiplier not supported") }
459 );
460
461 unsafe {
463 StatsSet::new_unchecked(smallvec![
464 (Stat::IsSorted, StatPrecision::Exact(is_sorted.into())),
465 (
466 Stat::IsStrictSorted,
467 StatPrecision::Exact(is_strict_sorted.into()),
468 ),
469 ])
470 }
471 }
472
473 pub(crate) unsafe fn new_unchecked(
481 base: PValue,
482 multiplier: PValue,
483 ptype: PType,
484 nullability: Nullability,
485 length: usize,
486 ) -> SequenceArray {
487 let dtype = DType::Primitive(ptype, nullability);
488 let (base, multiplier) = SequenceData::normalize(base, multiplier, ptype)
489 .vortex_expect("SequenceArray parts must be representable in the output ptype");
490 let stats = Self::stats(multiplier);
491 let data = unsafe { SequenceData::new_unchecked(base, multiplier) };
492 unsafe { Array::from_parts_unchecked(ArrayParts::new(Sequence, dtype, length, data)) }
493 .with_stats_set(stats)
494 }
495
496 pub fn try_new(
498 base: PValue,
499 multiplier: PValue,
500 ptype: PType,
501 nullability: Nullability,
502 length: usize,
503 ) -> VortexResult<SequenceArray> {
504 let dtype = DType::Primitive(ptype, nullability);
505 let data = SequenceData::try_new(base, multiplier, ptype, nullability, length)?;
506 let stats = Self::stats(data.multiplier());
507 Ok(
508 unsafe { Array::from_parts_unchecked(ArrayParts::new(Sequence, dtype, length, data)) }
509 .with_stats_set(stats),
510 )
511 }
512
513 pub fn try_new_typed<T: NativePType + Into<PValue>>(
515 base: T,
516 multiplier: T,
517 nullability: Nullability,
518 length: usize,
519 ) -> VortexResult<SequenceArray> {
520 let ptype = T::PTYPE;
521 let dtype = DType::Primitive(ptype, nullability);
522 let data = SequenceData::try_new_typed(base, multiplier, nullability, length)?;
523 let stats = Self::stats(data.multiplier());
524 Ok(
525 unsafe { Array::from_parts_unchecked(ArrayParts::new(Sequence, dtype, length, data)) }
526 .with_stats_set(stats),
527 )
528 }
529}
530
531#[cfg(test)]
532mod tests {
533 use std::sync::LazyLock;
534
535 use rstest::rstest;
536 use vortex_array::ArrayContext;
537 use vortex_array::ArrayEq;
538 use vortex_array::EqMode;
539 use vortex_array::IntoArray;
540 use vortex_array::VortexSessionExecute;
541 use vortex_array::arrays::PrimitiveArray;
542 use vortex_array::assert_arrays_eq;
543 use vortex_array::dtype::DType;
544 use vortex_array::dtype::Nullability;
545 use vortex_array::dtype::PType;
546 use vortex_array::expr::stats::Precision as StatPrecision;
547 use vortex_array::expr::stats::Stat;
548 use vortex_array::expr::stats::StatsProviderExt;
549 use vortex_array::scalar::PValue;
550 use vortex_array::scalar::Scalar;
551 use vortex_array::scalar::ScalarValue;
552 use vortex_array::serde::SerializeOptions;
553 use vortex_array::serde::SerializedArray;
554 use vortex_buffer::ByteBufferMut;
555 use vortex_error::VortexResult;
556 use vortex_error::vortex_err;
557 use vortex_session::VortexSession;
558 use vortex_session::registry::ReadContext;
559
560 use crate::Sequence;
561
562 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
563 let session = vortex_array::array_session();
564 crate::initialize(&session);
565 session
566 });
567
568 #[test]
569 fn test_sequence_canonical() {
570 let arr = Sequence::try_new_typed(2i64, 3, Nullability::NonNullable, 4).unwrap();
571
572 let canon = PrimitiveArray::from_iter((0..4).map(|i| 2i64 + i * 3));
573
574 assert_arrays_eq!(arr, canon, &mut SESSION.create_execution_ctx());
575 }
576
577 #[test]
578 fn test_sequence_slice_canonical() {
579 let arr = Sequence::try_new_typed(2i64, 3, Nullability::NonNullable, 4)
580 .unwrap()
581 .slice(2..3)
582 .unwrap();
583
584 let canon = PrimitiveArray::from_iter((2..3).map(|i| 2i64 + i * 3));
585
586 assert_arrays_eq!(arr, canon, &mut SESSION.create_execution_ctx());
587 }
588
589 #[test]
590 fn test_sequence_scalar_at() {
591 let scalar = Sequence::try_new_typed(2i64, 3, Nullability::NonNullable, 4)
592 .unwrap()
593 .execute_scalar(2, &mut SESSION.create_execution_ctx())
594 .unwrap();
595
596 assert_eq!(
597 scalar,
598 Scalar::try_new(scalar.dtype().clone(), Some(ScalarValue::from(8i64))).unwrap()
599 )
600 }
601
602 #[test]
603 fn test_sequence_min_max() {
604 assert!(Sequence::try_new_typed(-127i8, -1i8, Nullability::NonNullable, 2).is_ok());
605 assert!(Sequence::try_new_typed(126i8, -1i8, Nullability::NonNullable, 2).is_ok());
606 }
607
608 #[test]
609 fn test_sequence_too_big() {
610 assert!(Sequence::try_new_typed(127i8, 1i8, Nullability::NonNullable, 2).is_err());
611 assert!(Sequence::try_new_typed(-128i8, -1i8, Nullability::NonNullable, 2).is_err());
612 }
613
614 #[test]
615 fn positive_multiplier_is_strict_sorted() -> VortexResult<()> {
616 let arr = Sequence::try_new_typed(0i64, 3, Nullability::NonNullable, 4)?;
617
618 let is_sorted = arr
619 .statistics()
620 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsSorted));
621 assert_eq!(is_sorted, StatPrecision::Exact(true));
622
623 let is_strict_sorted = arr
624 .statistics()
625 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsStrictSorted));
626 assert_eq!(is_strict_sorted, StatPrecision::Exact(true));
627 Ok(())
628 }
629
630 #[test]
631 fn zero_multiplier_is_sorted_not_strict() -> VortexResult<()> {
632 let arr = Sequence::try_new_typed(5i64, 0, Nullability::NonNullable, 4)?;
633
634 let is_sorted = arr
635 .statistics()
636 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsSorted));
637 assert_eq!(is_sorted, StatPrecision::Exact(true));
638
639 let is_strict_sorted = arr
640 .statistics()
641 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsStrictSorted));
642 assert_eq!(is_strict_sorted, StatPrecision::Exact(false));
643 Ok(())
644 }
645
646 #[test]
647 fn negative_multiplier_not_sorted() -> VortexResult<()> {
648 let arr = Sequence::try_new_typed(10i64, -1, Nullability::NonNullable, 4)?;
649
650 let is_sorted = arr
651 .statistics()
652 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsSorted));
653 assert_eq!(is_sorted, StatPrecision::Exact(false));
654
655 let is_strict_sorted = arr
656 .statistics()
657 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsStrictSorted));
658 assert_eq!(is_strict_sorted, StatPrecision::Exact(false));
659 Ok(())
660 }
661
662 #[test]
665 fn test_large_multiplier_sorted() -> VortexResult<()> {
666 let large_multiplier = (i64::MAX as u64) + 1;
667 let arr = Sequence::try_new_typed(0, large_multiplier, Nullability::NonNullable, 2)?;
668
669 let is_sorted = arr
670 .statistics()
671 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsSorted));
672
673 let is_strict_sorted = arr
674 .statistics()
675 .with_typed_stats_set(|s| s.get_as::<bool>(Stat::IsStrictSorted));
676
677 assert_eq!(is_sorted, StatPrecision::Exact(true));
678 assert_eq!(is_strict_sorted, StatPrecision::Exact(true));
679
680 Ok(())
681 }
682
683 #[rstest]
684 #[case::descending_step_unsigned_output(PValue::from(100i32), PValue::from(-10i32), PType::U8)]
685 #[case::narrow_unsigned(PValue::from(1000u32), PValue::from(100u32), PType::U16)]
686 #[case::signed_output(PValue::from(0i16), PValue::from(1i16), PType::I32)]
687 #[case::signed_step_past_i64_max(PValue::from(0i64), PValue::from(1i64 << 62), PType::U64)]
688 #[case::unsigned_step_past_i64_max(PValue::from(0u64), PValue::from(u64::MAX / 4), PType::U64)]
689 fn serde_roundtrip_preserves_values(
690 #[case] base: PValue,
691 #[case] multiplier: PValue,
692 #[case] output_ptype: PType,
693 ) -> VortexResult<()> {
694 let array = Sequence::try_new(base, multiplier, output_ptype, Nullability::NonNullable, 4)?;
695 assert_eq!(array.ptype(), output_ptype);
696
697 let dtype = array.dtype().clone();
698 let len = array.len();
699 let ctx = ArrayContext::empty();
700 let serialized =
701 array
702 .clone()
703 .into_array()
704 .serialize(&ctx, &SESSION, &SerializeOptions::default())?;
705
706 let mut concat = ByteBufferMut::empty();
707 for buf in serialized {
708 concat.extend_from_slice(buf.as_ref());
709 }
710
711 let decoded = SerializedArray::try_from(concat.freeze())?.decode(
712 &dtype,
713 len,
714 &ReadContext::new(ctx.to_ids()),
715 &SESSION,
716 )?;
717
718 let decoded_sequence = decoded
719 .as_opt::<Sequence>()
720 .ok_or_else(|| vortex_err!("decoded array should still be a SequenceArray"))?;
721 assert_eq!(decoded_sequence.ptype(), output_ptype);
722 assert_eq!(decoded_sequence.multiplier(), array.multiplier());
723 assert_eq!(decoded.dtype(), &dtype);
724 assert_arrays_eq!(decoded, array, &mut SESSION.create_execution_ctx());
725
726 Ok(())
727 }
728
729 #[test]
730 fn descending_step_unsigned_output() -> VortexResult<()> {
731 let mut ctx = SESSION.create_execution_ctx();
732 let array = Sequence::try_new(
733 PValue::from(100i32),
734 PValue::from(-10i32),
735 PType::U8,
736 Nullability::NonNullable,
737 5,
738 )?;
739
740 assert_arrays_eq!(
741 array,
742 PrimitiveArray::from_iter([100u8, 90, 80, 70, 60]),
743 &mut ctx
744 );
745 assert_eq!(
746 array.clone().into_array().execute_scalar(1, &mut ctx)?,
747 Scalar::from(90u8)
748 );
749 assert_arrays_eq!(
750 array.slice(3..5)?,
751 PrimitiveArray::from_iter([70u8, 60]),
752 &mut ctx
753 );
754
755 Ok(())
756 }
757
758 #[test]
759 fn step_spanning_output_range() -> VortexResult<()> {
760 let array = Sequence::try_new(
761 PValue::from(255u8),
762 PValue::from(-255i32),
763 PType::U8,
764 Nullability::NonNullable,
765 2,
766 )?;
767
768 assert_arrays_eq!(
769 array,
770 PrimitiveArray::from_iter([255u8, 0]),
771 &mut SESSION.create_execution_ctx()
772 );
773
774 Ok(())
775 }
776
777 #[test]
778 fn values_past_i64_max() -> VortexResult<()> {
779 let mut ctx = SESSION.create_execution_ctx();
780 let step = 1u64 << 62;
781 let array = Sequence::try_new(
782 PValue::from(0i64),
783 PValue::from(1i64 << 62),
784 PType::U64,
785 Nullability::NonNullable,
786 4,
787 )?;
788
789 assert_arrays_eq!(
790 array,
791 PrimitiveArray::from_iter([0, step, 2 * step, 3 * step]),
792 &mut ctx
793 );
794 assert_eq!(
795 array.into_array().execute_scalar(3, &mut ctx)?,
796 Scalar::from(3 * step)
797 );
798
799 Ok(())
800 }
801
802 #[test]
803 fn eq_across_step_signedness() -> VortexResult<()> {
804 let base = PValue::from((1u64 << 63) - 1);
805 let descending = Sequence::try_new(
806 base,
807 PValue::from(-1i64),
808 PType::U64,
809 Nullability::NonNullable,
810 2,
811 )?
812 .into_array();
813 let ascending = Sequence::try_new(
814 base,
815 PValue::from(1u64 << 63),
816 PType::U64,
817 Nullability::NonNullable,
818 2,
819 )?
820 .into_array();
821
822 assert!(descending.array_eq(&descending.clone(), EqMode::Value));
823 assert!(!descending.array_eq(&ascending, EqMode::Value));
824
825 Ok(())
826 }
827
828 #[test]
829 fn constant_sequence_longer_than_output_range() -> VortexResult<()> {
830 let array = Sequence::try_new(
831 PValue::from(7u8),
832 PValue::from(0i32),
833 PType::U8,
834 Nullability::NonNullable,
835 300,
836 )?;
837
838 assert_arrays_eq!(
839 array,
840 PrimitiveArray::from_iter([7u8; 300]),
841 &mut SESSION.create_execution_ctx()
842 );
843
844 Ok(())
845 }
846
847 #[test]
848 fn deserialize_rejects_values_outside_output_ptype() -> VortexResult<()> {
849 let array = Sequence::try_new_typed(-5i32, 1i32, Nullability::NonNullable, 5)?;
850 let len = array.len();
851 let ctx = ArrayContext::empty();
852 let serialized =
853 array
854 .into_array()
855 .serialize(&ctx, &SESSION, &SerializeOptions::default())?;
856
857 let mut concat = ByteBufferMut::empty();
858 for buf in serialized {
859 concat.extend_from_slice(buf.as_ref());
860 }
861
862 let decoded = SerializedArray::try_from(concat.freeze())?.decode(
863 &DType::Primitive(PType::U8, Nullability::NonNullable),
864 len,
865 &ReadContext::new(ctx.to_ids()),
866 &SESSION,
867 );
868 assert!(decoded.is_err());
869
870 Ok(())
871 }
872}