Skip to main content

arrow/
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//! A complete, safe, native Rust implementation of [Apache Arrow](https://arrow.apache.org), a cross-language
6//! development platform for in-memory data.
7//!
8//! Please see the [arrow crates.io](https://crates.io/crates/arrow)
9//! page for feature flags and tips to improve performance.
10//!
11//! # Platform Support
12//!
13//! Only little-endian platforms are officially supported and tested in CI.
14//! Big-endian platforms are not tested in CI and may not work correctly.
15//! Fixes for big-endian platforms are welcome and handled on a best-effort basis,
16//! but compatibility is not guaranteed.
17//!
18//! # Columnar Format
19//!
20//! The [`array`] module provides statically typed implementations of all the array types as defined
21//! by the [Arrow Columnar Format](https://arrow.apache.org/docs/format/Columnar.html)
22//!
23//! For example, an [`Int32Array`](array::Int32Array) represents a nullable array of `i32`
24//!
25//! ```rust
26//! # use arrow::array::{Array, Int32Array};
27//! let array = Int32Array::from(vec![Some(1), None, Some(3)]);
28//! assert_eq!(array.len(), 3);
29//! assert_eq!(array.value(0), 1);
30//! assert_eq!(array.is_null(1), true);
31//!
32//! let collected: Vec<_> = array.iter().collect();
33//! assert_eq!(collected, vec![Some(1), None, Some(3)]);
34//! assert_eq!(array.values(), &[1, 0, 3])
35//! ```
36//!
37//! It is also possible to write generic code for different concrete types.
38//! For example, since the following function is generic over all primitively
39//! typed arrays, when invoked the Rust compiler will generate specialized implementations
40//! with optimized code for each concrete type.
41//!
42//! ```rust
43//! # use std::iter::Sum;
44//! # use arrow::array::{Float32Array, PrimitiveArray, TimestampNanosecondArray};
45//! # use arrow::datatypes::ArrowPrimitiveType;
46//! #
47//! fn sum<T: ArrowPrimitiveType>(array: &PrimitiveArray<T>) -> T::Native
48//! where
49//!     T: ArrowPrimitiveType,
50//!     T::Native: Sum
51//! {
52//!     array.iter().map(|v| v.unwrap_or_default()).sum()
53//! }
54//!
55//! assert_eq!(sum(&Float32Array::from(vec![1.1, 2.9, 3.])), 7.);
56//! assert_eq!(sum(&TimestampNanosecondArray::from(vec![1, 2, 3])), 6);
57//! ```
58//!
59//! And the following uses [`ArrayAccessor`] to implement a generic function
60//! over all arrays with comparable values.
61//!
62//! [`ArrayAccessor`]: array::ArrayAccessor
63//!
64//! ```rust
65//! # use arrow::array::{ArrayAccessor, ArrayIter, Int32Array, StringArray};
66//! # use arrow::datatypes::ArrowPrimitiveType;
67//! #
68//! fn min<T: ArrayAccessor>(array: T) -> Option<T::Item>
69//! where
70//!     T::Item: Ord
71//! {
72//!     ArrayIter::new(array).filter_map(|v| v).min()
73//! }
74//!
75//! assert_eq!(min(&Int32Array::from(vec![4, 2, 1, 6])), Some(1));
76//! assert_eq!(min(&StringArray::from(vec!["b", "a", "c"])), Some("a"));
77//! ```
78//!
79//! **For more examples, and details consult the [arrow_array] docs.**
80//!
81//! # Type Erasure / Trait Objects
82//!
83//! It is common to write code that handles any type of array, without necessarily
84//! knowing its concrete type. This is done using the [`Array`] trait and using
85//! [`DataType`] to determine the appropriate `downcast_ref`.
86//!
87//! [`DataType`]: datatypes::DataType
88//!
89//! ```rust
90//! # use arrow::array::{Array, Float32Array};
91//! # use arrow::array::StringArray;
92//! # use arrow::datatypes::DataType;
93//! #
94//! fn impl_string(array: &StringArray) {}
95//! fn impl_f32(array: &Float32Array) {}
96//!
97//! fn impl_dyn(array: &dyn Array) {
98//!     match array.data_type() {
99//!         // downcast `dyn Array` to concrete `StringArray`
100//!         DataType::Utf8 => impl_string(array.as_any().downcast_ref().unwrap()),
101//!         // downcast `dyn Array` to concrete `Float32Array`
102//!         DataType::Float32 => impl_f32(array.as_any().downcast_ref().unwrap()),
103//!         _ => unimplemented!()
104//!     }
105//! }
106//! ```
107//!
108//! You can use the [`AsArray`] extension trait to facilitate downcasting:
109//!
110//! [`AsArray`]: crate::array::AsArray
111//!
112//! ```rust
113//! # use arrow::array::{Array, Float32Array, AsArray};
114//! # use arrow::array::StringArray;
115//! # use arrow::datatypes::DataType;
116//! #
117//! fn impl_string(array: &StringArray) {}
118//! fn impl_f32(array: &Float32Array) {}
119//!
120//! fn impl_dyn(array: &dyn Array) {
121//!     match array.data_type() {
122//!         DataType::Utf8 => impl_string(array.as_string()),
123//!         DataType::Float32 => impl_f32(array.as_primitive()),
124//!         _ => unimplemented!()
125//!     }
126//! }
127//! ```
128//!
129//! It is also common to want to write a function that returns one of a number of possible
130//! array implementations. [`ArrayRef`] is a type-alias for [`Arc<dyn Array>`](array::Array)
131//! which is frequently used for this purpose
132//!
133//! ```rust
134//! # use std::str::FromStr;
135//! # use std::sync::Arc;
136//! # use arrow::array::{ArrayRef, Int32Array, PrimitiveArray};
137//! # use arrow::datatypes::{ArrowPrimitiveType, DataType, Int32Type, UInt32Type};
138//! # use arrow::compute::cast;
139//! #
140//! fn parse_to_primitive<'a, T, I>(iter: I) -> PrimitiveArray<T>
141//! where
142//!     T: ArrowPrimitiveType,
143//!     T::Native: FromStr,
144//!     I: IntoIterator<Item=&'a str>,
145//! {
146//!     PrimitiveArray::from_iter(iter.into_iter().map(|val| T::Native::from_str(val).ok()))
147//! }
148//!
149//! fn parse_strings<'a, I>(iter: I, to_data_type: DataType) -> ArrayRef
150//! where
151//!     I: IntoIterator<Item=&'a str>,
152//! {
153//!    match to_data_type {
154//!        DataType::Int32 => Arc::new(parse_to_primitive::<Int32Type, _>(iter)) as _,
155//!        DataType::UInt32 => Arc::new(parse_to_primitive::<UInt32Type, _>(iter)) as _,
156//!        _ => unimplemented!()
157//!    }
158//! }
159//!
160//! let array = parse_strings(["1", "2", "3"], DataType::Int32);
161//! let integers = array.as_any().downcast_ref::<Int32Array>().unwrap();
162//! assert_eq!(integers.values(), &[1, 2, 3])
163//! ```
164//!
165//! # Compute Kernels
166//!
167//! The [`compute`] module provides optimised implementations of many common operations,
168//! for example the `parse_strings` operation above could also be implemented as follows:
169//!
170//! ```
171//! # use std::sync::Arc;
172//! # use arrow::error::Result;
173//! # use arrow::array::{ArrayRef, StringArray, UInt32Array};
174//! # use arrow::datatypes::DataType;
175//! #
176//! fn parse_strings<'a, I>(iter: I, to_data_type: &DataType) -> Result<ArrayRef>
177//! where
178//!     I: IntoIterator<Item=&'a str>,
179//! {
180//!     let array = StringArray::from_iter(iter.into_iter().map(Some));
181//!     arrow::compute::cast(&array, to_data_type)
182//! }
183//!
184//! let array = parse_strings(["1", "2", "3"], &DataType::UInt32).unwrap();
185//! let integers = array.as_any().downcast_ref::<UInt32Array>().unwrap();
186//! assert_eq!(integers.values(), &[1, 2, 3])
187//! ```
188//!
189//! This module also implements many common vertical operations:
190//!
191//! * All mathematical binary operators, such as [`sub`](compute::kernels::numeric::sub)
192//! * All boolean binary operators such as [`equality`](compute::kernels::cmp::eq)
193//! * [`cast`](compute::kernels::cast::cast)
194//! * [`filter`](compute::kernels::filter::filter)
195//! * [`take`](compute::kernels::take::take)
196//! * [`sort`](compute::kernels::sort::sort)
197//! * some string operators such as [`substring`](compute::kernels::substring::substring) and [`length`](compute::kernels::length::length)
198//!
199//! ```
200//! # use arrow::compute::kernels::cmp::gt;
201//! # use arrow_array::cast::AsArray;
202//! # use arrow_array::Int32Array;
203//! # use arrow_array::types::Int32Type;
204//! # use arrow_select::filter::filter;
205//! let array = Int32Array::from_iter(0..100);
206//! // Create a 32-bit integer scalar (single) value:
207//! let scalar = Int32Array::new_scalar(60);
208//! // find all rows in the array that are greater than 60
209//! let predicate = gt(&array, &scalar).unwrap();
210//! // copy all matching rows into a new array
211//! let filtered = filter(&array, &predicate).unwrap();
212//!
213//! let expected = Int32Array::from_iter(61..100);
214//! assert_eq!(&expected, filtered.as_primitive::<Int32Type>());
215//! ```
216//!
217//! As well as some horizontal operations, such as:
218//!
219//! * [`min`](compute::kernels::aggregate::min) and [`max`](compute::kernels::aggregate::max)
220//! * [`sum`](compute::kernels::aggregate::sum)
221//!
222//! # Tabular Representation
223//!
224//! It is common to want to group one or more columns together into a tabular representation. This
225//! is provided by [`RecordBatch`] which combines a [`Schema`](datatypes::Schema)
226//! and a corresponding list of [`ArrayRef`].
227//!
228//!
229//! ```
230//! # use std::sync::Arc;
231//! # use arrow::array::{Float32Array, Int32Array};
232//! # use arrow::record_batch::RecordBatch;
233//! #
234//! let col_1 = Arc::new(Int32Array::from_iter([1, 2, 3])) as _;
235//! let col_2 = Arc::new(Float32Array::from_iter([1., 6.3, 4.])) as _;
236//!
237//! let batch = RecordBatch::try_from_iter([("col1", col_1), ("col_2", col_2)]).unwrap();
238//! ```
239//!
240//! # Pretty Printing
241//!
242//! See the [`util::pretty`] module (requires the `prettyprint` crate feature)
243//!
244//! # IO
245//!
246//! This crate provides readers and writers for various formats to/from [`RecordBatch`]
247//!
248//! * JSON: [`Reader`](json::reader::Reader) and [`Writer`](json::writer::Writer)
249//! * CSV: [`Reader`](csv::reader::Reader) and [`Writer`](csv::writer::Writer)
250//! * IPC: [`Reader`](ipc::reader::StreamReader) and [`Writer`](ipc::writer::FileWriter)
251//!
252//! Support for [Apache Parquet] is published as a [separate parquet crate](https://crates.io/crates/parquet)
253//!
254//! Support for [Apache Avro] is published as a [separate arrow-avro crate](https://crates.io/crates/arrow-avro)
255//!
256//! # Serde Compatibility
257//!
258//! [`arrow_json::reader::Decoder`] provides a mechanism to convert arbitrary, serde-compatible
259//! structures into [`RecordBatch`].
260//!
261//! Whilst likely less performant than implementing a custom builder, as described in
262//! [arrow_array::builder], this provides a simple mechanism to get up and running quickly
263//!
264//! ```
265//! # use std::sync::Arc;
266//! # use arrow_json::ReaderBuilder;
267//! # use arrow_schema::{DataType, Field, Schema};
268//! # use serde::Serialize;
269//! # use arrow_array::cast::AsArray;
270//! # use arrow_array::types::{Float32Type, Int32Type};
271//! #
272//! #[derive(Serialize)]
273//! struct MyStruct {
274//!     int32: i32,
275//!     string: String,
276//! }
277//!
278//! let schema = Schema::new(vec![
279//!     Field::new("int32", DataType::Int32, false),
280//!     Field::new("string", DataType::Utf8, false),
281//! ]);
282//!
283//! let rows = vec![
284//!     MyStruct{ int32: 5, string: "bar".to_string() },
285//!     MyStruct{ int32: 8, string: "foo".to_string() },
286//! ];
287//!
288//! let mut decoder = ReaderBuilder::new(Arc::new(schema)).build_decoder().unwrap();
289//! decoder.serialize(&rows).unwrap();
290//!
291//! let batch = decoder.flush().unwrap().unwrap();
292//!
293//! // Expect batch containing two columns
294//! let int32 = batch.column(0).as_primitive::<Int32Type>();
295//! assert_eq!(int32.values(), &[5, 8]);
296//!
297//! let string = batch.column(1).as_string::<i32>();
298//! assert_eq!(string.value(0), "bar");
299//! assert_eq!(string.value(1), "foo");
300//! ```
301//!
302//! # Crate Topology
303//!
304//! The [`arrow`] project is implemented as multiple sub-crates, which are then re-exported by
305//! this top-level crate.
306//!
307//! Crate authors can choose to depend on this top-level crate, or just
308//! the sub-crates they need.
309//!
310//! The current list of sub-crates is:
311//!
312//! * [`arrow-arith`][arrow_arith] - arithmetic kernels
313//! * [`arrow-array`][arrow_array] - type-safe arrow array abstractions
314//! * [`arrow-buffer`][arrow_buffer] - buffer abstractions for arrow arrays
315//! * [`arrow-cast`][arrow_cast] - cast kernels for arrow arrays
316//! * [`arrow-csv`][arrow_csv] - read/write CSV to arrow format
317//! * [`arrow-data`][arrow_data] - the underlying data of arrow arrays
318//! * [`arrow-ipc`][arrow_ipc] - read/write IPC to arrow format
319//! * [`arrow-json`][arrow_json] - read/write JSON to arrow format
320//! * [`arrow-ord`][arrow_ord] - ordering kernels for arrow arrays
321//! * [`arrow-row`][arrow_row] - comparable row format
322//! * [`arrow-schema`][arrow_schema] - the logical types for arrow arrays
323//! * [`arrow-select`][arrow_select] - selection kernels for arrow arrays
324//! * [`arrow-string`][arrow_string] - string kernels for arrow arrays
325//!
326//! Some functionality is also distributed independently of this crate:
327//!
328//! * [`arrow-flight`] - support for [Arrow Flight RPC]
329//! * [`parquet`](https://docs.rs/parquet) - support for [Apache Parquet]
330//! * [`arrow-avro`](https://docs.rs/arrow-avro) - support for [Apache Avro]
331//!
332//! # Security
333//!
334//! This project follows the [Apache Arrow Security Model].
335//!
336//! Unexpected behavior (e.g., panics, crashes, or infinite loops) triggered by
337//! malformed input is considered a **bug**, not a security vulnerability,
338//! unless it is **exploitable** by an attacker to
339//!
340//! * Execute arbitrary code (Remote Code Execution);
341//! * Exfiltrate sensitive information from process memory (Information Disclosure);
342//!
343//! If you think you have found a security vulnerability, please follow the
344//! reporting instructions in the [security policy].
345//!
346//! [security policy]: https://github.com/apache/arrow-rs/blob/main/SECURITY.md
347//!
348//! # Safety
349//!
350//! Like many crates, this crate makes use of `unsafe` where prudent. However, it endeavors to be
351//! sound. Specifically, **it should not be possible to trigger undefined behavior using safe APIs.**
352//!
353//! Undefined behavior using safe APIs is considered a bug, not a security
354//! vulnerability, unless it can be exploited. Please see the [security policy]
355//! for details.
356//!
357//! For more information on the use of `unsafe`, see [here](https://github.com/apache/arrow-rs/tree/main/arrow#safety).
358//!
359//! [Apache Arrow Security Model]: https://arrow.apache.org/docs/dev/format/Security.html
360//!
361//! # Higher-level Processing
362//!
363//! This crate aims to provide reusable, low-level primitives for operating on columnar data. For
364//! more sophisticated query processing workloads, consider checking out [DataFusion]. This
365//! orchestrates the primitives exported by this crate into an embeddable query engine, with
366//! SQL and DataFrame frontends, and heavily influences this crate's roadmap.
367//!
368//! [`arrow`]: https://github.com/apache/arrow-rs
369//! [`array`]: mod@array
370//! [`Array`]: array::Array
371//! [`ArrayRef`]: array::ArrayRef
372//! [`ArrayData`]: array::ArrayData
373//! [`make_array`]: array::make_array
374//! [`Buffer`]: buffer::Buffer
375//! [`RecordBatch`]: record_batch::RecordBatch
376//! [`arrow-flight`]: https://docs.rs/arrow-flight/latest/arrow_flight/
377//! [`parquet`]: https://docs.rs/parquet/latest/parquet/
378//! [Arrow Flight RPC]: https://arrow.apache.org/docs/format/Flight.html
379//! [Arrow JSON Test Format]: https://github.com/apache/arrow/blob/master/docs/source/format/Integration.rst#json-test-data-format
380//! [Apache Parquet]: https://parquet.apache.org/
381//! [Apache Avro]: https://avro.apache.org/
382//! [DataFusion]: https://github.com/apache/arrow-datafusion
383//! [issue tracker]: https://github.com/apache/arrow-rs/issues
384
385#![doc(
386    html_logo_url = "https://arrow.apache.org/img/arrow-logo_chevrons_black-txt_white-bg.svg",
387    html_favicon_url = "https://arrow.apache.org/img/arrow-logo_chevrons_black-txt_transparent-bg.svg"
388)]
389#![cfg_attr(docsrs, feature(doc_cfg))]
390#![deny(clippy::redundant_clone)]
391#![warn(missing_debug_implementations)]
392#![warn(missing_docs)]
393#![allow(rustdoc::invalid_html_tags)]
394pub use arrow_array::{downcast_dictionary_array, downcast_primitive_array};
395
396pub use arrow_buffer::{alloc, buffer};
397
398/// Arrow crate version
399pub const ARROW_VERSION: &str = env!("CARGO_PKG_VERSION");
400
401pub mod array;
402pub mod compute;
403#[cfg(feature = "csv")]
404pub use arrow_csv as csv;
405pub mod datatypes;
406pub mod error;
407#[cfg(feature = "ffi")]
408pub use arrow_array::ffi;
409#[cfg(feature = "ffi")]
410pub use arrow_array::ffi_stream;
411#[cfg(feature = "ipc")]
412pub use arrow_ipc as ipc;
413#[cfg(feature = "json")]
414pub use arrow_json as json;
415#[cfg(feature = "pyarrow")]
416pub use arrow_pyarrow as pyarrow;
417
418/// Contains the `RecordBatch` type and associated traits
419pub mod record_batch {
420    pub use arrow_array::{
421        RecordBatch, RecordBatchIterator, RecordBatchOptions, RecordBatchReader, RecordBatchWriter,
422    };
423}
424pub use arrow_array::temporal_conversions;
425pub use arrow_row as row;
426pub mod tensor;
427pub mod util;