arrow_array/scalar.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5use crate::Array;
6
7/// A possibly [`Scalar`] [`Array`]
8///
9/// This allows optimised binary kernels where one or more arguments are constant
10///
11/// ```
12/// # use arrow_array::*;
13/// # use arrow_buffer::{BooleanBuffer, MutableBuffer, NullBuffer};
14/// # use arrow_schema::ArrowError;
15/// #
16/// fn eq_impl<T: ArrowPrimitiveType>(
17/// a: &PrimitiveArray<T>,
18/// a_scalar: bool,
19/// b: &PrimitiveArray<T>,
20/// b_scalar: bool,
21/// ) -> BooleanArray {
22/// let (array, scalar) = match (a_scalar, b_scalar) {
23/// (true, true) | (false, false) => {
24/// let len = a.len().min(b.len());
25/// let nulls = NullBuffer::union(a.nulls(), b.nulls());
26/// let buffer = BooleanBuffer::collect_bool(len, |idx| a.value(idx) == b.value(idx));
27/// return BooleanArray::new(buffer, nulls);
28/// }
29/// (true, false) => (b, (a.null_count() == 0).then(|| a.value(0))),
30/// (false, true) => (a, (b.null_count() == 0).then(|| b.value(0))),
31/// };
32/// match scalar {
33/// Some(v) => {
34/// let len = array.len();
35/// let nulls = array.nulls().cloned();
36/// let buffer = BooleanBuffer::collect_bool(len, |idx| array.value(idx) == v);
37/// BooleanArray::new(buffer, nulls)
38/// }
39/// None => BooleanArray::new_null(array.len()),
40/// }
41/// }
42///
43/// pub fn eq(l: &dyn Datum, r: &dyn Datum) -> Result<BooleanArray, ArrowError> {
44/// let (l_array, l_scalar) = l.get();
45/// let (r_array, r_scalar) = r.get();
46/// downcast_primitive_array!(
47/// (l_array, r_array) => Ok(eq_impl(l_array, l_scalar, r_array, r_scalar)),
48/// (a, b) => Err(ArrowError::NotYetImplemented(format!("{a} == {b}"))),
49/// )
50/// }
51///
52/// // Comparison of two arrays
53/// let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
54/// let b = Int32Array::from(vec![1, 2, 4, 7, 3]);
55/// let r = eq(&a, &b).unwrap();
56/// let values: Vec<_> = r.values().iter().collect();
57/// assert_eq!(values, &[true, true, false, false, false]);
58///
59/// // Comparison of an array and a scalar
60/// let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
61/// let b = Int32Array::new_scalar(1);
62/// let r = eq(&a, &b).unwrap();
63/// let values: Vec<_> = r.values().iter().collect();
64/// assert_eq!(values, &[true, false, false, false, false]);
65/// ```
66pub trait Datum {
67 /// Returns the value for this [`Datum`] and a boolean indicating if the value is scalar
68 fn get(&self) -> (&dyn Array, bool);
69}
70
71impl<T: Array> Datum for T {
72 fn get(&self) -> (&dyn Array, bool) {
73 (self, false)
74 }
75}
76
77impl Datum for dyn Array {
78 fn get(&self) -> (&dyn Array, bool) {
79 (self, false)
80 }
81}
82
83impl Datum for &dyn Array {
84 fn get(&self) -> (&dyn Array, bool) {
85 (*self, false)
86 }
87}
88
89/// A wrapper around a single value [`Array`] that implements
90/// [`Datum`] and indicates [compute] kernels should treat this array
91/// as a scalar value (a single value).
92///
93/// Using a [`Scalar`] is often much more efficient than creating an
94/// [`Array`] with the same (repeated) value.
95///
96/// See [`Datum`] for more information.
97///
98/// # Example
99///
100/// ```rust
101/// # use arrow_array::{Scalar, Int32Array, ArrayRef};
102/// # fn get_array() -> ArrayRef { std::sync::Arc::new(Int32Array::from(vec![42])) }
103/// // Create a (typed) scalar for Int32Array for the value 42
104/// let scalar = Scalar::new(Int32Array::from(vec![42]));
105///
106/// // Create a scalar using PrimitiveArray::scalar
107/// let scalar = Int32Array::new_scalar(42);
108///
109/// // create a scalar from an ArrayRef (for dynamic typed Arrays)
110/// let array: ArrayRef = get_array();
111/// let scalar = Scalar::new(array);
112/// ```
113///
114/// [compute]: https://docs.rs/arrow/latest/arrow/compute/index.html
115#[derive(Debug, Copy, Clone)]
116pub struct Scalar<T: Array>(T);
117
118impl<T: Array> Scalar<T> {
119 /// Create a new [`Scalar`] from an [`Array`]
120 ///
121 /// # Panics
122 ///
123 /// Panics if `array.len() != 1`
124 pub fn new(array: T) -> Self {
125 assert_eq!(array.len(), 1);
126 Self(array)
127 }
128
129 /// Returns the inner array
130 #[inline]
131 pub fn into_inner(self) -> T {
132 self.0
133 }
134}
135
136impl<T: Array> Datum for Scalar<T> {
137 fn get(&self) -> (&dyn Array, bool) {
138 (&self.0, true)
139 }
140}