Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ Search for `expect(clippy::` in the codebase to identify lints that are intentio
- If you have several lints on a function or module, you may disable the lint on the function or module.
- If a lint is pervasive across multiple modules, you may disable it at the crate level.

Tests, benchmarks and the helpers they use are free to panic, so they carry a file-level
`#![expect(clippy::missing_panics_doc, ...)]` rather than a `# Panics` section per function.
Public helper modules such as `arrow::util::bench_util` say so in their module docs, since
the file-level suppression hides the panics from their own documentation.

## Performance Improvements

Pull requests that improve performance, especially those that add non-trivial complexity or use `unsafe`, should include evidence of the improvement, such as benchmarks.
Expand Down
8 changes: 8 additions & 0 deletions arrow-arith/src/arity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ where
///
/// Return an error if the arrays have different lengths or
/// the operation is under erroneous
#[expect(
clippy::missing_panics_doc,
reason = "the null buffers of two equal-length arrays with nulls always combine"
)]
pub fn try_binary<A: ArrayAccessor, B: ArrayAccessor, F, O>(
a: A,
b: B,
Expand Down Expand Up @@ -302,6 +306,10 @@ where
/// Like [`try_unary`] the function is only evaluated for non-null indices.
///
/// See [`binary_mut`] for errors and buffer reuse information.
#[expect(
clippy::missing_panics_doc,
reason = "the null buffers of two equal-length arrays with nulls always combine"
)]
pub fn try_binary_mut<T, F>(
a: PrimitiveArray<T>,
b: &PrimitiveArray<T>,
Expand Down
4 changes: 4 additions & 0 deletions arrow-array/src/array/dictionary_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,10 @@ impl<K: ArrowDictionaryKeyType> DictionaryArray<K> {
/// Returns `PrimitiveDictionaryBuilder` of this dictionary array for mutating
/// its keys and values if the underlying data buffer is not shared by others.
#[expect(clippy::result_large_err)]
#[expect(
clippy::missing_panics_doc,
reason = "rebuilding the dictionary from its own keys and values always succeeds"
)]
pub fn into_primitive_dict_builder<V>(self) -> Result<PrimitiveDictionaryBuilder<K, V>, Self>
where
V: ArrowPrimitiveType,
Expand Down
4 changes: 4 additions & 0 deletions arrow-array/src/array/list_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ impl<OffsetSize: OffsetSizeTrait> GenericListArray<OffsetSize> {
/// * `offsets.last() > values.len()`
/// * `!field.is_nullable() && values.is_nullable()`
/// * `field.data_type() != values.data_type()`
#[expect(
clippy::missing_panics_doc,
reason = "an `OffsetBuffer` is never empty"
)]
pub fn try_new(
field: FieldRef,
offsets: OffsetBuffer<OffsetSize>,
Expand Down
4 changes: 4 additions & 0 deletions arrow-array/src/array/map_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ impl MapArray {
/// * `entries.columns().len() != 2`
/// * `field.data_type() != entries.data_type()`
/// * the keys field is nullable
#[expect(
clippy::missing_panics_doc,
reason = "an `OffsetBuffer` is never empty"
)]
pub fn try_new(
field: FieldRef,
offsets: OffsetBuffer<i32>,
Expand Down
4 changes: 4 additions & 0 deletions arrow-array/src/array/union_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@ impl UnionArray {
/// # Ok(())
/// # }
/// ```
#[expect(
clippy::missing_panics_doc,
reason = "a `UnionArray` always has a union data type with a child per type id"
)]
pub fn into_parts(
self,
) -> (
Expand Down
4 changes: 4 additions & 0 deletions arrow-array/src/builder/generic_bytes_view_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,10 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
/// # Ok::<(), arrow_schema::ArrowError>(())
/// ```
#[inline]
#[expect(
clippy::missing_panics_doc,
reason = "`try_append_value` always pushes exactly one view"
)]
pub fn try_append_value_n(
&mut self,
value: impl AsRef<T::Native>,
Expand Down
4 changes: 4 additions & 0 deletions arrow-buffer/src/buffer/immutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ impl Buffer {
/// ```
///
/// [`ALIGNMENT`]: crate::alloc::ALIGNMENT
#[expect(
clippy::missing_panics_doc,
reason = "the buffer has no offset, so it starts at the allocation pointer"
)]
pub fn into_mutable(self) -> Result<MutableBuffer, Self> {
let ptr = self.ptr;
let length = self.length;
Expand Down
4 changes: 4 additions & 0 deletions arrow-cast/src/cast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,10 @@ fn timestamp_to_date32<T: ArrowTimestampType>(
/// // NOTE: the timestamp is adjusted (08:33:20 instead of 03:33:20 as in previous example)
/// assert_eq!("2033-05-18T08:33:20", display::array_value_to_string(&d, 1).unwrap());
/// ```
#[expect(
clippy::missing_panics_doc,
reason = "an array always matches the concrete type of its data type"
)]
pub fn cast_with_options(
array: &dyn Array,
to_type: &DataType,
Expand Down
4 changes: 4 additions & 0 deletions arrow-data/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ impl ArrayData {
/// or [`ArrayDataBuilder`].
///
/// See also [`Self::into_parts`] to recover the fields
#[expect(
clippy::missing_panics_doc,
reason = "the local builder is never set to skip validation"
)]
pub fn try_new(
data_type: DataType,
len: usize,
Expand Down
4 changes: 4 additions & 0 deletions arrow-flight/src/sql/metadata/sql_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ pub struct SqlInfoData {
impl SqlInfoData {
/// Return a [`RecordBatch`] containing only the requested `u32`, if any
/// from [`CommandGetSqlInfo`]
#[expect(
clippy::missing_panics_doc,
reason = "the filters are built from the same array, so they have equal length"
)]
pub fn record_batch(&self, info: impl IntoIterator<Item = u32>) -> Result<RecordBatch> {
let arr = self.batch.column(0);
let type_filter = info
Expand Down
4 changes: 4 additions & 0 deletions arrow-flight/src/sql/metadata/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ impl GetTablesBuilder {
}

/// builds a `RecordBatch` for `CommandGetTables`
#[expect(
clippy::missing_panics_doc,
reason = "the filters are built from the same array, so they have equal length"
)]
pub fn build(self) -> Result<RecordBatch> {
let schema = self.schema();
let Self {
Expand Down
2 changes: 2 additions & 0 deletions arrow-flight/tests/flight_sql_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.

#![expect(clippy::missing_panics_doc, reason = "tests are free to panic")]

mod common;

use crate::common::fixture::TestFixture;
Expand Down
2 changes: 2 additions & 0 deletions arrow-flight/tests/flight_sql_client_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.

#![expect(clippy::missing_panics_doc, reason = "tests are free to panic")]

mod common;

use std::{pin::Pin, sync::Arc};
Expand Down
4 changes: 4 additions & 0 deletions arrow-integration-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,10 @@ impl ArrowJsonBatch {
/// to an empty `ArrowJsonColumn`.
///
/// </div>
#[expect(
clippy::missing_panics_doc,
reason = "a column always matches the concrete type of its data type"
)]
pub fn from_batch(batch: &RecordBatch) -> ArrowJsonBatch {
let mut json_batch = ArrowJsonBatch {
count: batch.num_rows(),
Expand Down
4 changes: 4 additions & 0 deletions arrow-integration-testing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
// The unused_crate_dependencies lint does not work well for crates defining additional examples/bin targets
#![allow(unused_crate_dependencies)]
#![warn(missing_docs)]
#![expect(
clippy::missing_panics_doc,
reason = "these are integration test binaries, which are free to panic"
)]
use serde_json::Value;

use arrow::array::{Array, StructArray};
Expand Down
4 changes: 4 additions & 0 deletions arrow-ipc/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,10 @@ impl FileDecoder {
}

/// Read the dictionary with the given block and data buffer
#[expect(
clippy::missing_panics_doc,
reason = "the header type was just checked to be a dictionary batch"
)]
pub fn read_dictionary(&mut self, block: &Block, buf: &Buffer) -> Result<(), ArrowError> {
let message = self.read_message(buf)?;
match message.header_type() {
Expand Down
4 changes: 4 additions & 0 deletions arrow-ipc/src/reader/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ impl StreamDecoder {
/// Ok(())
/// }
/// ```
#[expect(
clippy::missing_panics_doc,
reason = "the header type was just checked to be a record batch"
)]
pub fn decode(&mut self, buffer: &mut Buffer) -> Result<Option<RecordBatch>, ArrowError> {
while !buffer.is_empty() {
match &mut self.state {
Expand Down
4 changes: 4 additions & 0 deletions arrow-json/src/writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ where
}

/// Serialize `batch` to JSON output
#[expect(
clippy::missing_panics_doc,
reason = "the root of a `RecordBatch` is never nullable"
)]
pub fn write(&mut self, batch: &RecordBatch) -> Result<(), ArrowError> {
if batch.num_rows() == 0 {
return Ok(());
Expand Down
4 changes: 4 additions & 0 deletions arrow-schema/src/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ impl Fields {
/// ]);
/// assert_eq!(filtered, expected);
/// ```
#[expect(
clippy::missing_panics_doc,
reason = "the predicate passed to `try_filter_leaves` is infallible"
)]
pub fn filter_leaves<F: FnMut(usize, &FieldRef) -> bool>(&self, mut filter: F) -> Self {
self.try_filter_leaves(|idx, field| Ok(filter(idx, field)))
.unwrap()
Expand Down
8 changes: 8 additions & 0 deletions arrow-string/src/concat_elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ pub fn concat_element_binary<Offset: OffsetSizeTrait>(
/// ```
///
/// An error will be returned if the [`StringArray`] are of different lengths
#[expect(
clippy::missing_panics_doc,
reason = "the offsets of an array of length `size` always yield `size + 1` values"
)]
pub fn concat_elements_utf8_many<Offset: OffsetSizeTrait>(
arrays: &[&GenericStringArray<Offset>],
) -> Result<GenericStringArray<Offset>, ArrowError> {
Expand Down Expand Up @@ -414,6 +418,10 @@ pub fn concat_elements_string_view_array(
/// # Errors
///
/// This function errors if the arrays are of different types.
#[expect(
clippy::missing_panics_doc,
reason = "an array always matches the concrete type of its data type"
)]
pub fn concat_elements_dyn(left: &dyn Array, right: &dyn Array) -> Result<ArrayRef, ArrowError> {
match (left.data_type(), right.data_type()) {
(DataType::Utf8, DataType::Utf8) => {
Expand Down
8 changes: 8 additions & 0 deletions arrow/src/util/bench_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
// under the License.

//! Utils to make benchmarking easier
//!
//! These helpers are meant for benchmarks, so they panic on invalid input
//! instead of reporting it. The individual functions do not repeat that.

#![expect(
clippy::missing_panics_doc,
reason = "benchmark helpers are free to panic"
)]

use crate::array::*;
use crate::datatypes::*;
Expand Down
4 changes: 4 additions & 0 deletions arrow/src/util/data_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ pub fn create_random_batch(
/// * `null_density` - The approximate fraction of null values in the resulting array (0.0 to 1.0)
/// * `true_density` - The approximate fraction of true values in boolean arrays (0.0 to 1.0)
///
#[expect(
clippy::missing_panics_doc,
reason = "the null density is set to zero for non-nullable fields"
)]
pub fn create_random_array(
field: &Field,
size: usize,
Expand Down
5 changes: 5 additions & 0 deletions arrow/src/util/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
// under the License.

//! Utils to make testing easier
//!
//! These helpers are meant for tests, so they panic on invalid input instead of
//! reporting it. The individual functions do not repeat that.

#![expect(clippy::missing_panics_doc, reason = "test helpers are free to panic")]

use rand::{RngExt, SeedableRng, rngs::StdRng};
use std::{env, error::Error, fs, io::Write, path::PathBuf};
Expand Down
2 changes: 2 additions & 0 deletions parquet-variant-compute/benches/variant_kernels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.

#![expect(clippy::missing_panics_doc, reason = "benchmarks are free to panic")]

use arrow::array::{Array, ArrayRef, BinaryViewArray, BinaryViewBuilder, StringArray, StructArray};
use arrow::buffer::Buffer;
use arrow_schema::{DataType, Field, FieldRef, Fields};
Expand Down
4 changes: 4 additions & 0 deletions parquet-variant-compute/src/variant_array_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ impl VariantArrayBuilder {
}

/// Build the final builder
#[expect(
clippy::missing_panics_doc,
reason = "the builder only produces valid variant arrays"
)]
pub fn build(self) -> VariantArray {
let Self {
mut nulls,
Expand Down
2 changes: 2 additions & 0 deletions parquet/benches/parquet_round_trip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.

#![expect(clippy::missing_panics_doc, reason = "benchmarks are free to panic")]

use arrow::array::{ArrayRef, RecordBatch};
use arrow::datatypes::{DataType, Field, Float32Type, Float64Type, Int32Type, Int64Type, Schema};
use arrow::util::bench_util::{
Expand Down
4 changes: 4 additions & 0 deletions parquet/src/arrow/arrow_reader/statistics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,10 @@ impl<'a> StatisticsConverter<'a> {
/// extract the column offset index on a per row group per column basis.
///
/// See docs on [`Self::data_page_mins`] for details.
#[expect(
clippy::missing_panics_doc,
reason = "a page location list in the offset index is never empty"
)]
pub fn data_page_row_counts<I>(
&self,
column_offset_index: &ParquetOffsetIndex,
Expand Down
4 changes: 4 additions & 0 deletions parquet/src/bloom_filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@ impl Sbbf {

/// Create a new [Sbbf] with given number of bytes, the exact number of bytes will be adjusted
/// to the next power of two bounded by [BITSET_MIN_LENGTH] and [BITSET_MAX_LENGTH].
#[expect(
clippy::missing_panics_doc,
reason = "`optimal_num_of_bytes` always returns a multiple of the block size"
)]
pub fn new_with_num_of_bytes(num_bytes: usize) -> Self {
let num_bytes = optimal_num_of_bytes(num_bytes);
assert_eq!(num_bytes % size_of::<Block>(), 0);
Expand Down
4 changes: 4 additions & 0 deletions parquet/src/file/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,10 @@ impl<'a, W: Write + Send> SerializedRowGroupWriter<'a, W> {
}

/// Closes this row group writer and returns row group metadata.
#[expect(
clippy::missing_panics_doc,
reason = "the row group metadata is set just above"
)]
pub fn close(mut self) -> Result<RowGroupMetaDataPtr> {
if self.row_group_metadata.is_none() {
self.assert_previous_writer_closed()?;
Expand Down
Loading