arrow_array/lib.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
5//! The central type in Apache Arrow are arrays, which are a known-length sequence of values
6//! all having the same type. This crate provides concrete implementations of each type, as
7//! well as an [`Array`] trait that can be used for type-erasure.
8//!
9//! # Building an Array
10//!
11//! Most [`Array`] implementations can be constructed directly from iterators or [`Vec`]
12//!
13//! ```
14//! # use arrow_array::{Int32Array, ListArray, StringArray};
15//! # use arrow_array::types::Int32Type;
16//! #
17//! Int32Array::from(vec![1, 2]);
18//! Int32Array::from(vec![Some(1), None]);
19//! Int32Array::from_iter([1, 2, 3, 4]);
20//! Int32Array::from_iter([Some(1), Some(2), None, Some(4)]);
21//!
22//! StringArray::from(vec!["foo", "bar"]);
23//! StringArray::from(vec![Some("foo"), None]);
24//! StringArray::from_iter([Some("foo"), None]);
25//! StringArray::from_iter_values(["foo", "bar"]);
26//!
27//! ListArray::from_iter_primitive::<Int32Type, _, _>([
28//! Some(vec![Some(1), None, Some(3)]),
29//! None,
30//! Some(vec![])
31//! ]);
32//! ```
33//!
34//! Additionally [`ArrayBuilder`](builder::ArrayBuilder) implementations can be
35//! used to construct arrays with a push-based interface
36//!
37//! ```
38//! # use arrow_array::Int16Array;
39//! #
40//! // Create a new builder with a capacity of 100
41//! let mut builder = Int16Array::builder(100);
42//!
43//! // Append a single primitive value
44//! builder.append_value(1);
45//! // Append a null value
46//! builder.append_null();
47//! // Append a slice of primitive values
48//! builder.append_slice(&[2, 3, 4]);
49//!
50//! // Build the array
51//! let array = builder.finish();
52//!
53//! assert_eq!(5, array.len());
54//! assert_eq!(2, array.value(2));
55//! assert_eq!(&array.values()[3..5], &[3, 4])
56//! ```
57//!
58//! # Low-level API
59//!
60//! Internally, arrays consist of one or more shared memory regions backed by a [`Buffer`],
61//! the number and meaning of which depend on the array’s data type, as documented in
62//! the [Arrow specification].
63//!
64//! For example, the type [`Int16Array`] represents an array of 16-bit integers and consists of:
65//!
66//! * An optional [`NullBuffer`] identifying any null values
67//! * A contiguous [`ScalarBuffer<i16>`] of values
68//!
69//! Similarly, the type [`StringArray`] represents an array of UTF-8 strings and consists of:
70//!
71//! * An optional [`NullBuffer`] identifying any null values
72//! * An offsets [`OffsetBuffer<i32>`] identifying valid UTF-8 sequences within the values buffer
73//! * A values [`Buffer`] of UTF-8 encoded string data
74//!
75//! Array constructors such as [`PrimitiveArray::try_new`] provide the ability to cheaply
76//! construct an array from these parts, with functions such as [`PrimitiveArray::into_parts`]
77//! providing the reverse operation.
78//!
79//! ```
80//! # use arrow_array::{Array, Int32Array, StringArray};
81//! # use arrow_buffer::OffsetBuffer;
82//! #
83//! // Create a Int32Array from Vec without copying
84//! let array = Int32Array::new(vec![1, 2, 3].into(), None);
85//! assert_eq!(array.values(), &[1, 2, 3]);
86//! assert_eq!(array.null_count(), 0);
87//!
88//! // Create a StringArray from parts
89//! let offsets = OffsetBuffer::new(vec![0, 5, 10].into());
90//! let array = StringArray::new(offsets, b"helloworld".into(), None);
91//! let values: Vec<_> = array.iter().map(|x| x.unwrap()).collect();
92//! assert_eq!(values, &["hello", "world"]);
93//! ```
94//!
95//! As [`Buffer`], and its derivatives, can be created from [`Vec`] without copying, this provides
96//! an efficient way to not only interoperate with other Rust code, but also implement kernels
97//! optimised for the arrow data layout - e.g. by handling buffers instead of values.
98//!
99//! # Zero-Copy Slicing
100//!
101//! Given an [`Array`] of arbitrary length, it is possible to create an owned slice of this
102//! data. Internally this just increments some ref-counts, and so is incredibly cheap
103//!
104//! ```rust
105//! # use arrow_array::Int32Array;
106//! let array = Int32Array::from_iter([1, 2, 3]);
107//!
108//! // Slice with offset 1 and length 2
109//! let sliced = array.slice(1, 2);
110//! assert_eq!(sliced.values(), &[2, 3]);
111//! ```
112//!
113//! # Downcasting an Array
114//!
115//! Arrays are often passed around as a dynamically typed [`&dyn Array`] or [`ArrayRef`].
116//! For example, [`RecordBatch`](`crate::RecordBatch`) stores columns as [`ArrayRef`].
117//!
118//! Whilst these arrays can be passed directly to the [`compute`], [`csv`], [`json`], etc... APIs,
119//! it is often the case that you wish to interact with the concrete arrays directly.
120//!
121//! This requires downcasting to the concrete type of the array:
122//!
123//! ```
124//! # use arrow_array::{Array, Float32Array, Int32Array};
125//!
126//! // Safely downcast an `Array` to an `Int32Array` and compute the sum
127//! // using native i32 values
128//! fn sum_int32(array: &dyn Array) -> i32 {
129//! let integers: &Int32Array = array.as_any().downcast_ref().unwrap();
130//! integers.iter().map(|val| val.unwrap_or_default()).sum()
131//! }
132//!
133//! // Safely downcasts the array to a `Float32Array` and returns a &[f32] view of the data
134//! // Note: the values for positions corresponding to nulls will be arbitrary (but still valid f32)
135//! fn as_f32_slice(array: &dyn Array) -> &[f32] {
136//! array.as_any().downcast_ref::<Float32Array>().unwrap().values()
137//! }
138//! ```
139//!
140//! The [`cast::AsArray`] extension trait can make this more ergonomic
141//!
142//! ```
143//! # use arrow_array::Array;
144//! # use arrow_array::cast::{AsArray, as_primitive_array};
145//! # use arrow_array::types::Float32Type;
146//!
147//! fn as_f32_slice(array: &dyn Array) -> &[f32] {
148//! array.as_primitive::<Float32Type>().values()
149//! }
150//! ```
151//! # Alternatives to ChunkedArray Support
152//!
153//! The Rust implementation does not provide the ChunkedArray abstraction implemented by the Python
154//! and C++ Arrow implementations. The recommended alternative is to use one of the following:
155//! - `Vec<ArrayRef>` a simple, eager version of a `ChunkedArray`
156//! - `impl Iterator<Item=ArrayRef>` a lazy version of a `ChunkedArray`
157//! - `impl Stream<Item=ArrayRef>` a lazy async version of a `ChunkedArray`
158//!
159//! Similar patterns can be applied at the `RecordBatch` level. For example, [DataFusion] makes
160//! extensive use of [RecordBatchStream].
161//!
162//! This approach integrates well into the Rust ecosystem, simplifies the implementation and
163//! encourages the use of performant lazy and async patterns.
164//! ```rust
165//! use std::sync::Arc;
166//! use arrow_array::{ArrayRef, Float32Array, RecordBatch, StringArray};
167//! use arrow_array::cast::AsArray;
168//! use arrow_array::types::Float32Type;
169//! use arrow_schema::DataType;
170//!
171//! let batches = [
172//! RecordBatch::try_from_iter(vec![
173//! ("label", Arc::new(StringArray::from(vec!["A", "B", "C"])) as ArrayRef),
174//! ("value", Arc::new(Float32Array::from(vec![0.1, 0.2, 0.3])) as ArrayRef),
175//! ]).unwrap(),
176//! RecordBatch::try_from_iter(vec![
177//! ("label", Arc::new(StringArray::from(vec!["D", "E"])) as ArrayRef),
178//! ("value", Arc::new(Float32Array::from(vec![0.4, 0.5])) as ArrayRef),
179//! ]).unwrap(),
180//! ];
181//!
182//! let labels: Vec<&str> = batches
183//! .iter()
184//! .flat_map(|batch| batch.column(0).as_string::<i32>())
185//! .map(Option::unwrap)
186//! .collect();
187//!
188//! let values: Vec<f32> = batches
189//! .iter()
190//! .flat_map(|batch| batch.column(1).as_primitive::<Float32Type>().values())
191//! .copied()
192//! .collect();
193//!
194//! assert_eq!(labels, ["A", "B", "C", "D", "E"]);
195//! assert_eq!(values, [0.1, 0.2, 0.3, 0.4, 0.5]);
196//!```
197//! [`ScalarBuffer<T>`]: arrow_buffer::ScalarBuffer
198//! [`ScalarBuffer<i16>`]: arrow_buffer::ScalarBuffer
199//! [`OffsetBuffer<i32>`]: arrow_buffer::OffsetBuffer
200//! [`NullBuffer`]: arrow_buffer::NullBuffer
201//! [Arrow specification]: https://arrow.apache.org/docs/format/Columnar.html
202//! [`&dyn Array`]: Array
203//! [`NullBuffer`]: arrow_buffer::NullBuffer
204//! [`Buffer`]: arrow_buffer::Buffer
205//! [`compute`]: https://docs.rs/arrow/latest/arrow/compute/index.html
206//! [`json`]: https://docs.rs/arrow/latest/arrow/json/index.html
207//! [`csv`]: https://docs.rs/arrow/latest/arrow/csv/index.html
208//! [DataFusion]: https://github.com/apache/arrow-datafusion
209//! [RecordBatchStream]: https://docs.rs/datafusion/latest/datafusion/execution/trait.RecordBatchStream.html
210//!
211//! # Platform Support
212//!
213//! Only little-endian platforms are officially supported and tested in CI.
214//! Big-endian platforms are not tested in CI and may not work correctly.
215//! Fixes for big-endian platforms are welcome and handled on a best-effort basis,
216//! but compatibility is not guaranteed.
217
218#![doc(
219 html_logo_url = "https://arrow.apache.org/img/arrow-logo_chevrons_black-txt_white-bg.svg",
220 html_favicon_url = "https://arrow.apache.org/img/arrow-logo_chevrons_black-txt_transparent-bg.svg"
221)]
222#![cfg_attr(docsrs, feature(doc_cfg))]
223#![deny(rustdoc::broken_intra_doc_links)]
224#![warn(missing_docs)]
225
226/// Arrow crate version
227pub const ARROW_VERSION: &str = env!("CARGO_PKG_VERSION");
228
229pub mod array;
230pub use array::*;
231
232mod array_reader;
233pub use array_reader::{ArrayIterator, ArrayReader};
234
235mod record_batch;
236pub use record_batch::{
237 RecordBatch, RecordBatchIterator, RecordBatchOptions, RecordBatchReader, RecordBatchWriter,
238};
239
240mod arithmetic;
241pub use arithmetic::ArrowNativeTypeOp;
242
243mod numeric;
244pub use numeric::*;
245
246mod scalar;
247pub use scalar::*;
248
249pub mod builder;
250pub mod cast;
251mod delta;
252#[cfg(feature = "ffi")]
253pub mod ffi;
254#[cfg(feature = "ffi")]
255pub mod ffi_stream;
256pub mod iterator;
257#[cfg(feature = "async")]
258pub mod nonblocking;
259pub mod run_iterator;
260pub mod temporal_conversions;
261pub mod timezone;
262mod trusted_len;
263pub mod types;
264
265#[cfg(test)]
266mod tests {
267 use crate::builder::*;
268
269 #[test]
270 fn test_buffer_builder_availability() {
271 let _builder = Int8BufferBuilder::new(10);
272 let _builder = Int16BufferBuilder::new(10);
273 let _builder = Int32BufferBuilder::new(10);
274 let _builder = Int64BufferBuilder::new(10);
275 let _builder = UInt16BufferBuilder::new(10);
276 let _builder = UInt32BufferBuilder::new(10);
277 let _builder = Float32BufferBuilder::new(10);
278 let _builder = Float64BufferBuilder::new(10);
279 let _builder = TimestampSecondBufferBuilder::new(10);
280 let _builder = TimestampMillisecondBufferBuilder::new(10);
281 let _builder = TimestampMicrosecondBufferBuilder::new(10);
282 let _builder = TimestampNanosecondBufferBuilder::new(10);
283 let _builder = Date32BufferBuilder::new(10);
284 let _builder = Date64BufferBuilder::new(10);
285 let _builder = Time32SecondBufferBuilder::new(10);
286 let _builder = Time32MillisecondBufferBuilder::new(10);
287 let _builder = Time64MicrosecondBufferBuilder::new(10);
288 let _builder = Time64NanosecondBufferBuilder::new(10);
289 let _builder = IntervalYearMonthBufferBuilder::new(10);
290 let _builder = IntervalDayTimeBufferBuilder::new(10);
291 let _builder = IntervalMonthDayNanoBufferBuilder::new(10);
292 let _builder = DurationSecondBufferBuilder::new(10);
293 let _builder = DurationMillisecondBufferBuilder::new(10);
294 let _builder = DurationMicrosecondBufferBuilder::new(10);
295 let _builder = DurationNanosecondBufferBuilder::new(10);
296 }
297}