Skip to content

Add UnionScalar#8739

Open
connortsui20 wants to merge 2 commits into
developfrom
ct/union-scalar
Open

Add UnionScalar#8739
connortsui20 wants to merge 2 commits into
developfrom
ct/union-scalar

Conversation

@connortsui20

@connortsui20 connortsui20 commented Jul 13, 2026

Copy link
Copy Markdown
Member

Rationale for this change

Tracking Issue: #7882

UnionScalar is the row representation needed for scalar access and constant arrays before the canonical UnionArray. Non-null values store the selected type ID and child ScalarValue; null remains on the outer Scalar, avoiding a second null layer.

What changes are included in this PR?

  • add UnionValue, UnionScalar, construction, downcasts, validation, display, equality, hashing, defaults, and sizing
  • add scalar protobuf round trips and keep non-identity Union casts unsupported
  • add arbitrary generation and ConstantArray scalar access coverage

Tested with cargo nextest run -p vortex-array and cargo clippy --all-targets --all-features.

What APIs are changed? Are there any user-facing changes?

Adds ScalarValue::Union, UnionValue, UnionScalar, Scalar::union, and the Union scalar downcasts.

Signed-off-by: "Connor Tsui" <connor.tsui20@gmail.com>
@codspeed-hq

codspeed-hq Bot commented Jul 13, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚡ 6 improved benchmarks
❌ 7 regressed benchmarks
✅ 1651 untouched benchmarks
⏩ 42 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation chunked_varbinview_into_canonical[(1000, 10)] 169.5 µs 206.6 µs -17.95%
Simulation chunked_varbinview_opt_canonical_into[(1000, 10)] 168.9 µs 205.6 µs -17.84%
Simulation chunked_varbinview_into_canonical[(100, 100)] 272.2 µs 307.6 µs -11.51%
Simulation encode_varbin[(1000, 8)] 139.1 µs 156.2 µs -10.92%
Simulation encode_varbin[(1000, 32)] 144.1 µs 161.1 µs -10.56%
Simulation encode_varbin[(1000, 4)] 138.7 µs 155 µs -10.54%
Simulation encode_varbin[(1000, 2)] 138.3 µs 154.6 µs -10.54%
Simulation copy_nullable[65536] 1,027.8 µs 573.2 µs +79.3%
Simulation chunked_varbinview_opt_into_canonical[(1000, 10)] 219.8 µs 183.8 µs +19.63%
Simulation chunked_varbinview_canonical_into[(100, 100)] 258.5 µs 223.5 µs +15.68%
Simulation copy_non_nullable[65536] 908.5 µs 793.9 µs +14.44%
Simulation bitwise_not_vortex_buffer_mut[128] 244.4 ns 215.3 ns +13.55%
Simulation bitwise_not_vortex_buffer_mut[1024] 304.7 ns 275.6 ns +10.58%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ct/union-scalar (4893177) with develop (0aa35f4)

Open in CodSpeed

Footnotes

  1. 42 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@connortsui20 connortsui20 changed the title Add Union scalar support Add UnionScalar Jul 13, 2026
@connortsui20 connortsui20 force-pushed the ct/union-scalar branch 4 times, most recently from 7e619d3 to 243969b Compare July 13, 2026 16:08
Comment on lines +27 to +35
// Union nullability is part of its variant dtypes, so the generic nullability-only cast
// below is not valid for unions. Keep all non-identity union casts unsupported until their
// semantics are defined.
if matches!(self.dtype(), DType::Union(_)) || matches!(target_dtype, DType::Union(_)) {
vortex_bail!(
"non-identity union scalar cast from {} to {target_dtype} is not supported",
self.dtype()
);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interested in what people think about how we should deal with this

@connortsui20 connortsui20 force-pushed the ct/union-scalar branch 3 times, most recently from 8bb8db6 to 7925944 Compare July 13, 2026 19:41
/// We implement `Hash` manually so top-level dtype nullability does not affect the hash.
impl Hash for Scalar {
fn hash<H: Hasher>(&self, state: &mut H) {
// TODO(connor): Recursively ignore dtype nullability to match Scalar equality (#8744).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@connortsui20 connortsui20 force-pushed the ct/union-scalar branch 3 times, most recently from 43d2fc9 to 9de7663 Compare July 13, 2026 20:01
@connortsui20 connortsui20 added the changelog/feature A new feature label Jul 13, 2026
Base automatically changed from codex/reject-negative-union-type-ids to develop July 13, 2026 20:34
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20 connortsui20 marked this pull request as ready for review July 13, 2026 22:05
Comment on lines +63 to +67
dtype: &'a DType,
/// The variants of the union.
///
/// We store this here as a convenience so that we do not need to unwrap the dtype every time.
variants: &'a UnionVariants,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just store the nullability here so we don't need the DType at all?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/feature A new feature

2 participants