This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new f28db3e5b4 Introduce workspace lints (#10533)
f28db3e5b4 is described below

commit f28db3e5b4da944a1a21a69c3451ee2895e356e5
Author: Emil Ernerfeldt <[email protected]>
AuthorDate: Tue Aug 4 11:10:10 2026 -0700

    Introduce workspace lints (#10533)
    
    # Which issue does this PR close?
    No issue in particular
    
    - Related to #10458
    - Sibling PR: https://github.com/apache/datafusion/pull/24076
    
    # Rationale for this change
    
    Lint configuration is currently repeated per crate in `lib.rs`. A
    `[workspace.lints]` table lets us configure lints once, for every crate,
    and makes rolling out new lints a one-line change.
    
    Enabling more lints can also help keeping a higher code quality,
    reducing bugs.
    
    # What changes are included in this PR?
    
    Modeled on [egui's
    `Cargo.toml`](https://github.com/emilk/egui/blob/main/Cargo.toml). I
    started small. We can enable more lints in later PRs.
    
    # Are these changes tested?
    
    Yes, by existing CI: `cargo clippy --workspace --all-targets
    --all-features -- -D warnings` and the docs job
    (`RUSTDOCFLAGS=-Dwarnings`) both pass. Two previously-dead doc examples
    now actually compile and run.
    
    # Are there any user-facing changes?
    
    `parquet_variant_compute::VariantArrayIter` is now exported. It was
    already returned by the public `VariantArray::iter`, but was not
    nameable. No other API changes.
    
    ---------
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
    Co-authored-by: Andrew Lamb <[email protected]>
---
 CONTRIBUTING.md                                    | 11 ++++
 Cargo.toml                                         | 65 ++++++++++++++++++++++
 arrow-arith/Cargo.toml                             |  3 +
 arrow-array/Cargo.toml                             |  3 +
 arrow-array/src/array/boolean_array.rs             |  4 ++
 arrow-array/src/array/union_array.rs               |  4 +-
 arrow-array/src/builder/primitive_run_builder.rs   |  2 +-
 arrow-array/src/ffi_stream.rs                      | 10 ++--
 arrow-array/src/record_batch.rs                    |  2 +-
 arrow-avro/Cargo.toml                              |  3 +
 arrow-avro/src/codec.rs                            |  2 +-
 arrow-avro/src/schema.rs                           |  8 +--
 arrow-avro/src/writer/encoder.rs                   |  2 +-
 arrow-buffer/Cargo.toml                            |  3 +
 arrow-buffer/src/bigint/mod.rs                     |  2 +-
 arrow-buffer/src/buffer/immutable.rs               |  4 +-
 arrow-buffer/src/util/bit_iterator.rs              |  4 +-
 arrow-cast/Cargo.toml                              |  3 +
 arrow-cast/src/cast/mod.rs                         |  4 +-
 arrow-csv/Cargo.toml                               |  3 +
 arrow-data/Cargo.toml                              |  3 +
 arrow-data/src/decimal.rs                          |  2 +-
 arrow-data/src/ffi.rs                              |  2 +-
 arrow-flight/Cargo.toml                            |  3 +
 arrow-flight/gen/Cargo.toml                        |  3 +
 arrow-flight/gen/src/main.rs                       |  2 +
 arrow-flight/src/bin/flight_sql_client.rs          |  4 +-
 arrow-flight/src/encode.rs                         |  6 +-
 arrow-flight/src/sql/metadata/tables.rs            |  2 +-
 arrow-flight/tests/flight_sql_client.rs            | 16 ++----
 arrow-integration-test/Cargo.toml                  |  3 +
 arrow-integration-testing/Cargo.toml               |  3 +
 .../src/bin/arrow-file-to-stream.rs                |  2 +
 .../src/bin/arrow-json-integration-test.rs         |  2 +
 .../src/bin/arrow-stream-to-file.rs                |  2 +
 .../src/bin/flight-test-integration-client.rs      |  2 +
 .../src/bin/flight-test-integration-server.rs      |  2 +
 arrow-ipc/Cargo.toml                               |  3 +
 arrow-ipc/src/convert.rs                           |  2 +-
 arrow-ipc/src/reader.rs                            |  2 +-
 arrow-json/Cargo.toml                              |  3 +
 arrow-json/src/writer/encoder.rs                   |  2 +-
 arrow-ord/Cargo.toml                               |  3 +
 arrow-ord/src/sort.rs                              | 10 ++--
 arrow-pyarrow/Cargo.toml                           |  3 +
 arrow-row/Cargo.toml                               |  3 +
 arrow-row/src/lib.rs                               |  2 +-
 arrow-schema/Cargo.toml                            |  3 +
 arrow-schema/src/fields.rs                         | 16 ++----
 arrow-select/Cargo.toml                            |  3 +
 arrow-select/src/filter.rs                         |  6 +-
 arrow-select/src/merge.rs                          |  5 +-
 arrow-string/Cargo.toml                            |  3 +
 arrow/Cargo.toml                                   |  3 +
 arrow/src/util/test_util.rs                        |  9 +--
 arrow/tests/shrink_to_fit.rs                       |  1 -
 parquet-geospatial/Cargo.toml                      |  3 +
 parquet-geospatial/src/bounding.rs                 |  2 +-
 parquet-variant-compute/Cargo.toml                 |  3 +
 parquet-variant-compute/src/lib.rs                 |  2 +-
 parquet-variant-compute/src/variant_get.rs         |  2 +-
 parquet-variant-json/Cargo.toml                    |  3 +
 parquet-variant/Cargo.toml                         |  3 +
 parquet-variant/src/builder/list.rs                |  2 +-
 parquet-variant/src/utils.rs                       |  4 +-
 parquet/Cargo.toml                                 |  3 +
 parquet/benches/metadata.rs                        |  3 +-
 parquet/examples/write_parquet.rs                  |  2 +-
 parquet/src/arrow/arrow_reader/mod.rs              |  4 +-
 parquet/src/arrow/arrow_reader/statistics.rs       |  2 +-
 parquet/src/arrow/arrow_writer/levels.rs           |  4 +-
 parquet/src/arrow/push_decoder/mod.rs              |  2 +-
 parquet/src/arrow/schema/mod.rs                    |  2 +-
 parquet/src/arrow/schema/primitive.rs              |  2 +-
 parquet/src/bin/parquet-fromcsv.rs                 |  9 +--
 parquet/src/column/chunker/cdc.rs                  |  4 +-
 parquet/src/column/writer/encoder.rs               |  2 +-
 parquet/src/column/writer/mod.rs                   |  2 +-
 parquet/src/compression.rs                         |  4 +-
 parquet/src/errors.rs                              | 26 +++++++++
 parquet/src/file/metadata/push_decoder.rs          |  2 +-
 parquet/src/file/metadata/reader.rs                |  3 +-
 parquet/src/file/writer.rs                         |  6 +-
 parquet/src/parquet_thrift.rs                      |  2 +-
 parquet/src/util/test_common/file_util.rs          |  6 +-
 parquet/tests/arrow_reader/row_filter/async.rs     |  2 +-
 parquet_derive/Cargo.toml                          |  3 +
 parquet_derive_test/Cargo.toml                     |  3 +
 parquet_derive_test/src/lib.rs                     | 11 ++--
 89 files changed, 297 insertions(+), 119 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c2d57f20ca..5ff7cc98ab 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -190,6 +190,17 @@ cargo clippy --workspace --all-targets --all-features -- 
-D warnings
 
 If you use Visual Studio Code with the `rust-analyzer` plugin, you can enable 
`clippy` to run each time you save a file. See 
https://users.rust-lang.org/t/how-to-use-clippy-in-vs-code-with-rust-analyzer/41881.
 
+In addition to the lints that `clippy` enables by default, we enable a few 
extra ones in
+`[workspace.lints]` in the root `Cargo.toml`. Every crate in the workspace 
opts in to those with:
+
+```toml
+[lints]
+workspace = true
+```
+
+New crates should include that section, and new lints should be added to 
`[workspace.lints]`
+rather than to individual crates, so that they apply everywhere.
+
 One of the concerns with `clippy` is that it often produces a lot of false 
positives, or that some recommendations may hurt readability. We do not have a 
policy of which lints are ignored, but if you disagree with a `clippy` lint, 
you may disable the lint and briefly justify it.
 
 Search for `allow(clippy::` in the codebase to identify lints that are 
ignored/allowed. We currently prefer ignoring lints on the lowest unit possible.
diff --git a/Cargo.toml b/Cargo.toml
index e68517ee68..f317703955 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -112,6 +112,71 @@ object_store = { version = "0.14.1", default-features = 
false }
 
 simdutf8 = { version = "0.1.5", default-features = false }
 
+# Lints that are shared by every crate in the workspace.
+#
+# Each member crate opts in with:
+#
+#   [lints]
+#   workspace = true
+#
+# Only lints that are `allow` by default are worth listing here; the lints 
that clippy
+# enables by default are already enforced by CI (`cargo clippy ... -- -D 
warnings`).
+#
+# Keep the lists sorted.
+[workspace.lints.rust]
+future_incompatible = { level = "warn", priority = -1 }
+nonstandard_style = { level = "warn", priority = -1 }
+rust_2018_idioms = { level = "warn", priority = -1 }
+rust_2021_prelude_collisions = "warn"
+semicolon_in_expressions_from_macros = "warn"
+unsafe_op_in_unsafe_fn = "warn"
+unused_import_braces = "warn"
+
+# TODO: fix the violations and enable these too. They are all part of 
`rust_2018_idioms`,
+# and each has far too many violations to fix in one go:
+elided_lifetimes_in_paths = "allow"      # ~1200 violations
+explicit_outlives_requirements = "allow" # ~80 violations
+unused_extern_crates = "allow"           # ~60 violations
+
+[workspace.lints.rustdoc]
+all = { level = "warn", priority = -1 }
+broken_intra_doc_links = "warn"
+missing_crate_level_docs = "warn"
+
+[workspace.lints.clippy]
+bool_to_int_with_if = "warn"
+dbg_macro = "warn"
+debug_assert_with_mut_call = "warn"
+doc_comment_double_space_linebreaks = "warn"
+doc_include_without_cfg = "warn"
+flat_map_option = "warn"
+format_push_string = "warn"
+invalid_upcast_comparisons = "warn"
+iter_filter_is_some = "warn"
+iter_with_drain = "warn"
+literal_string_with_formatting_args = "warn"
+manual_instant_elapsed = "warn"
+match_wild_err_arm = "warn"
+mut_mut = "warn"
+mutex_integer = "warn"
+option_as_ref_cloned = "warn"
+path_buf_push_overwrite = "warn"
+pathbuf_init_then_push = "warn"
+ptr_offset_by_literal = "warn"
+rc_mutex = "warn"
+ref_binding_to_reference = "warn"
+same_length_and_capacity = "warn"
+should_panic_without_expect = "warn"
+single_char_pattern = "warn"
+stable_sort_primitive = "warn"
+trailing_empty_array = "warn"
+trait_duplication_in_bounds = "warn"
+unnecessary_box_returns = "warn"
+unnecessary_self_imports = "warn"
+unnecessary_struct_initialization = "warn"
+unused_peekable = "warn"
+zero_sized_map_values = "warn"
+
 # release inherited profile keeping debug information and symbols
 # for mem/cpu profiling
 [profile.profiling]
diff --git a/arrow-arith/Cargo.toml b/arrow-arith/Cargo.toml
index c3222eccf2..b5e1fcc257 100644
--- a/arrow-arith/Cargo.toml
+++ b/arrow-arith/Cargo.toml
@@ -49,3 +49,6 @@ criterion = { workspace = true }
 [[bench]]
 name = "decimal_arithmetic"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-array/Cargo.toml b/arrow-array/Cargo.toml
index c59c4fe4f2..126996ee64 100644
--- a/arrow-array/Cargo.toml
+++ b/arrow-array/Cargo.toml
@@ -108,3 +108,6 @@ harness = false
 [[bench]]
 name = "boolean_array"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-array/src/array/boolean_array.rs 
b/arrow-array/src/array/boolean_array.rs
index fee4e5b419..18b8fec448 100644
--- a/arrow-array/src/array/boolean_array.rs
+++ b/arrow-array/src/array/boolean_array.rs
@@ -1086,6 +1086,10 @@ mod tests {
     fn test_boolean_array_from_iter_with_larger_upper_bound() {
         // See https://github.com/apache/arrow-rs/issues/8505
         // This returns an upper size hint of 4
+        #[expect(
+            clippy::iter_filter_is_some,
+            reason = "the point of the test is the size hint of `filter`, 
which `flatten` does not have"
+        )]
         let iterator = vec![Some(true), None, Some(false), None]
             .into_iter()
             .filter(Option::is_some);
diff --git a/arrow-array/src/array/union_array.rs 
b/arrow-array/src/array/union_array.rs
index 5ba7b947c7..4f96ba49d8 100644
--- a/arrow-array/src/array/union_array.rs
+++ b/arrow-array/src/array/union_array.rs
@@ -928,7 +928,7 @@ unsafe impl Array for UnionArray {
         }
         self.fields
             .iter()
-            .flat_map(|x| x.as_ref().map(|x| x.get_buffer_memory_size()))
+            .filter_map(|x| x.as_ref().map(|x| x.get_buffer_memory_size()))
             .sum::<usize>()
             + sum
     }
@@ -942,7 +942,7 @@ unsafe impl Array for UnionArray {
             + self
                 .fields
                 .iter()
-                .flat_map(|x| x.as_ref().map(|x| x.get_array_memory_size()))
+                .filter_map(|x| x.as_ref().map(|x| x.get_array_memory_size()))
                 .sum::<usize>()
             + sum
     }
diff --git a/arrow-array/src/builder/primitive_run_builder.rs 
b/arrow-array/src/builder/primitive_run_builder.rs
index c1dc0d8d7d..8febc29294 100644
--- a/arrow-array/src/builder/primitive_run_builder.rs
+++ b/arrow-array/src/builder/primitive_run_builder.rs
@@ -328,7 +328,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic]
+    #[should_panic(expected = "incompatible data type for builder")]
     fn test_override_data_type_invalid() {
         PrimitiveRunBuilder::<Int16Type, 
UInt32Type>::new().with_data_type(DataType::UInt64);
     }
diff --git a/arrow-array/src/ffi_stream.rs b/arrow-array/src/ffi_stream.rs
index 9a09c3753d..011f3a8b0f 100644
--- a/arrow-array/src/ffi_stream.rs
+++ b/arrow-array/src/ffi_stream.rs
@@ -417,8 +417,8 @@ mod tests {
         pub fn new(
             schema: SchemaRef,
             iter: Box<dyn Iterator<Item = Result<RecordBatch>> + Send>,
-        ) -> Box<TestRecordBatchReader> {
-            Box::new(TestRecordBatchReader { schema, iter })
+        ) -> TestRecordBatchReader {
+            TestRecordBatchReader { schema, iter }
         }
     }
 
@@ -439,7 +439,7 @@ mod tests {
     fn _test_round_trip_export(batch: RecordBatch, schema: Arc<Schema>) -> 
Result<()> {
         let iter = Box::new(vec![batch.clone(), 
batch.clone()].into_iter().map(Ok)) as _;
 
-        let reader = TestRecordBatchReader::new(schema.clone(), iter);
+        let reader = Box::new(TestRecordBatchReader::new(schema.clone(), 
iter));
 
         // Export a `RecordBatchReader` through `FFI_ArrowArrayStream`
         let mut ffi_stream = FFI_ArrowArrayStream::new(reader);
@@ -484,7 +484,7 @@ mod tests {
     fn _test_round_trip_import(batch: RecordBatch, schema: Arc<Schema>) -> 
Result<()> {
         let iter = Box::new(vec![batch.clone(), 
batch.clone()].into_iter().map(Ok)) as _;
 
-        let reader = TestRecordBatchReader::new(schema.clone(), iter);
+        let reader = Box::new(TestRecordBatchReader::new(schema.clone(), 
iter));
 
         // Import through `FFI_ArrowArrayStream` as `ArrowArrayStreamReader`
         let stream = FFI_ArrowArrayStream::new(reader);
@@ -546,7 +546,7 @@ mod tests {
 
         let iter = 
Box::new(vec![Err(ArrowError::MemoryError("".to_string()))].into_iter());
 
-        let reader = TestRecordBatchReader::new(schema.clone(), iter);
+        let reader = Box::new(TestRecordBatchReader::new(schema.clone(), 
iter));
 
         // Import through `FFI_ArrowArrayStream` as `ArrowArrayStreamReader`
         let stream = FFI_ArrowArrayStream::new(reader);
diff --git a/arrow-array/src/record_batch.rs b/arrow-array/src/record_batch.rs
index 911604cd0b..78177a4d42 100644
--- a/arrow-array/src/record_batch.rs
+++ b/arrow-array/src/record_batch.rs
@@ -644,7 +644,7 @@ impl RecordBatch {
     ///
     /// # Panics
     ///
-    /// Panics if `index`` out of bounds.
+    /// Panics if `index` is out of bounds.
     ///
     /// # Example
     ///
diff --git a/arrow-avro/Cargo.toml b/arrow-avro/Cargo.toml
index a4c20f0553..ce210cf0e3 100644
--- a/arrow-avro/Cargo.toml
+++ b/arrow-avro/Cargo.toml
@@ -125,3 +125,6 @@ harness = false
 [[bench]]
 name = "project_record"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-avro/src/codec.rs b/arrow-avro/src/codec.rs
index e21d4df5c3..c4df569ba0 100644
--- a/arrow-avro/src/codec.rs
+++ b/arrow-avro/src/codec.rs
@@ -1198,7 +1198,7 @@ impl From<&Codec> for UnionFieldKind {
 
 fn union_branch_name(dt: &AvroDataType) -> String {
     if let Some(name) = dt.metadata.get(AVRO_NAME_METADATA_KEY) {
-        if name.contains(".") {
+        if name.contains('.') {
             // Full name
             return name.to_string();
         }
diff --git a/arrow-avro/src/schema.rs b/arrow-avro/src/schema.rs
index ece56c6e71..a22373ac6c 100644
--- a/arrow-avro/src/schema.rs
+++ b/arrow-avro/src/schema.rs
@@ -4011,7 +4011,7 @@ mod tests {
         let err = schema.project(&[5]).unwrap_err();
         let msg = err.to_string();
         assert!(
-            msg.contains("out of bounds") && msg.contains("5") && 
msg.contains("2"),
+            msg.contains("out of bounds") && msg.contains('5') && 
msg.contains('2'),
             "Expected out of bounds error, got: {msg}"
         );
     }
@@ -4030,7 +4030,7 @@ mod tests {
         let err = schema.project(&[1]).unwrap_err();
         let msg = err.to_string();
         assert!(
-            msg.contains("out of bounds") && msg.contains("1"),
+            msg.contains("out of bounds") && msg.contains('1'),
             "Expected out of bounds error for edge case, got: {msg}"
         );
     }
@@ -4050,7 +4050,7 @@ mod tests {
         let err = schema.project(&[0, 1, 0]).unwrap_err();
         let msg = err.to_string();
         assert!(
-            msg.contains("Duplicate projection index") && msg.contains("0"),
+            msg.contains("Duplicate projection index") && msg.contains('0'),
             "Expected duplicate index error, got: {msg}"
         );
     }
@@ -4069,7 +4069,7 @@ mod tests {
         let err = schema.project(&[1, 1]).unwrap_err();
         let msg = err.to_string();
         assert!(
-            msg.contains("Duplicate projection index") && msg.contains("1"),
+            msg.contains("Duplicate projection index") && msg.contains('1'),
             "Expected duplicate index error for consecutive duplicates, got: 
{msg}"
         );
     }
diff --git a/arrow-avro/src/writer/encoder.rs b/arrow-avro/src/writer/encoder.rs
index 23ace7d049..e88337cd6d 100644
--- a/arrow-avro/src/writer/encoder.rs
+++ b/arrow-avro/src/writer/encoder.rs
@@ -100,7 +100,7 @@ fn write_len_prefixed<W: Write + ?Sized>(out: &mut W, 
bytes: &[u8]) -> Result<()
 
 #[inline]
 fn write_bool<W: Write + ?Sized>(out: &mut W, v: bool) -> Result<(), 
AvroError> {
-    out.write_all(&[if v { 1 } else { 0 }])
+    out.write_all(&[u8::from(v)])
         .map_err(|e| AvroError::IoError(format!("write bool: {e}"), e))
 }
 
diff --git a/arrow-buffer/Cargo.toml b/arrow-buffer/Cargo.toml
index 86813e6141..6f36d9a0fa 100644
--- a/arrow-buffer/Cargo.toml
+++ b/arrow-buffer/Cargo.toml
@@ -64,3 +64,6 @@ harness = false
 [[bench]]
 name = "mutable_buffer_repeat_slice"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-buffer/src/bigint/mod.rs b/arrow-buffer/src/bigint/mod.rs
index dc61a5d0f0..81392c3c3a 100644
--- a/arrow-buffer/src/bigint/mod.rs
+++ b/arrow-buffer/src/bigint/mod.rs
@@ -1948,7 +1948,7 @@ mod tests {
         assert_eq!(!i256::ONE, i256::from_parts(u128::MAX - 1, -1));
     }
 
-    #[should_panic]
+    #[should_panic(expected = "rhs overflow for shift")]
     #[test]
     fn test_shl_panic_on_arg_overflow() {
         let value = i256::from(123);
diff --git a/arrow-buffer/src/buffer/immutable.rs 
b/arrow-buffer/src/buffer/immutable.rs
index bfccdf5538..c3821164e4 100644
--- a/arrow-buffer/src/buffer/immutable.rs
+++ b/arrow-buffer/src/buffer/immutable.rs
@@ -692,12 +692,12 @@ mod tests {
 
         assert_eq!([6, 8, 10], buf2.as_slice());
         assert_eq!(3, buf2.len());
-        assert_eq!(unsafe { buf.as_ptr().offset(2) }, buf2.as_ptr());
+        assert_eq!(unsafe { buf.as_ptr().add(2) }, buf2.as_ptr());
 
         let buf3 = buf2.slice_with_length(1, 2);
         assert_eq!([8, 10], buf3.as_slice());
         assert_eq!(2, buf3.len());
-        assert_eq!(unsafe { buf.as_ptr().offset(3) }, buf3.as_ptr());
+        assert_eq!(unsafe { buf.as_ptr().add(3) }, buf3.as_ptr());
 
         let buf4 = buf.slice(5);
         let empty_slice: [u8; 0] = [];
diff --git a/arrow-buffer/src/util/bit_iterator.rs 
b/arrow-buffer/src/util/bit_iterator.rs
index a1b2fec6ea..840a2c2df1 100644
--- a/arrow-buffer/src/util/bit_iterator.rs
+++ b/arrow-buffer/src/util/bit_iterator.rs
@@ -555,7 +555,7 @@ mod tests {
     #[test]
     fn test_bit_index_u32_long_all_set() {
         let len = 200;
-        let num_bytes = len / 8 + if len % 8 != 0 { 1 } else { 0 };
+        let num_bytes = len / 8 + usize::from(len % 8 != 0);
         let bytes = vec![0xFFu8; num_bytes];
 
         let result: Vec<u32> = BitIndexU32Iterator::new(&bytes, 0, 
len).collect();
@@ -568,7 +568,7 @@ mod tests {
     #[test]
     fn test_bit_index_u32_none_set() {
         let len = 50;
-        let num_bytes = len / 8 + if len % 8 != 0 { 1 } else { 0 };
+        let num_bytes = len / 8 + usize::from(len % 8 != 0);
         let bytes = vec![0u8; num_bytes];
 
         let result: Vec<u32> = BitIndexU32Iterator::new(&bytes, 0, 
len).collect();
diff --git a/arrow-cast/Cargo.toml b/arrow-cast/Cargo.toml
index 65646bfc2f..d3257f5894 100644
--- a/arrow-cast/Cargo.toml
+++ b/arrow-cast/Cargo.toml
@@ -76,3 +76,6 @@ harness = false
 [[bench]]
 name = "parse_decimal"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs
index 35dce48e68..d88fd2847b 100644
--- a/arrow-cast/src/cast/mod.rs
+++ b/arrow-cast/src/cast/mod.rs
@@ -646,7 +646,7 @@ fn timestamp_to_date32<T: ArrowTimestampType>(
 ///   has the wrong length it will be replaced with NULL, otherwise an error 
will be returned
 /// * Primitive to `List`: a list array with 1 value per slot is created
 /// * `Date32` and `Date64`: precision lost when going to higher interval
-/// * `Time32 and `Time64`: precision lost when going to higher interval
+/// * `Time32` and `Time64`: precision lost when going to higher interval
 /// * `Timestamp` and `Date{32|64}`: precision lost when going to higher 
interval
 /// * Temporal to/from backing Primitive: zero-copy with data type change
 /// * `Float16/Float32/Float64` to `Decimal(precision, scale)` rounds to the 
`scale` decimals
@@ -2616,7 +2616,7 @@ where
 
 fn numeric_to_bool_cast<T>(from: &PrimitiveArray<T>) -> Result<BooleanArray, 
ArrowError>
 where
-    T: ArrowPrimitiveType + ArrowPrimitiveType,
+    T: ArrowPrimitiveType,
 {
     let mut b = BooleanBuilder::with_capacity(from.len());
 
diff --git a/arrow-csv/Cargo.toml b/arrow-csv/Cargo.toml
index 689acf7b06..aa1cbc21f6 100644
--- a/arrow-csv/Cargo.toml
+++ b/arrow-csv/Cargo.toml
@@ -51,3 +51,6 @@ futures = "0.3"
 tokio = { version = "1.27", default-features = false, features = ["io-util"] }
 bytes = "1.4"
 half = { version = "2.1", default-features = false }
+
+[lints]
+workspace = true
diff --git a/arrow-data/Cargo.toml b/arrow-data/Cargo.toml
index 9f1b50ed14..3c51213474 100644
--- a/arrow-data/Cargo.toml
+++ b/arrow-data/Cargo.toml
@@ -57,3 +57,6 @@ half = { version = "2.1", default-features = false }
 [dev-dependencies]
 
 [build-dependencies]
+
+[lints]
+workspace = true
diff --git a/arrow-data/src/decimal.rs b/arrow-data/src/decimal.rs
index a5986755ad..8dc4328102 100644
--- a/arrow-data/src/decimal.rs
+++ b/arrow-data/src/decimal.rs
@@ -896,7 +896,7 @@ pub const MAX_DECIMAL32_FOR_EACH_PRECISION: [i32; 10] = [
     9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
 ];
 
-/// `MIN_DECIMAL32_FOR_EACH_PRECISION[p]` holds the minimum `ialue that can
+/// `MIN_DECIMAL32_FOR_EACH_PRECISION[p]` holds the minimum value that can
 /// be stored in a [`Decimal32`] value of precision `p`.
 ///
 /// # Notes
diff --git a/arrow-data/src/ffi.rs b/arrow-data/src/ffi.rs
index 80ccee6c8a..29107641c1 100644
--- a/arrow-data/src/ffi.rs
+++ b/arrow-data/src/ffi.rs
@@ -166,7 +166,7 @@ impl FFI_ArrowArray {
 
         let buffers_ptr = buffers
             .iter()
-            .flat_map(|maybe_buffer| match maybe_buffer {
+            .filter_map(|maybe_buffer| match maybe_buffer {
                 Some(b) => Some(b.as_ptr() as *const c_void),
                 // This is for null buffer. We only put a null pointer for
                 // null buffer if by spec it can contain null mask.
diff --git a/arrow-flight/Cargo.toml b/arrow-flight/Cargo.toml
index 0356219079..8062d0fa09 100644
--- a/arrow-flight/Cargo.toml
+++ b/arrow-flight/Cargo.toml
@@ -110,3 +110,6 @@ required-features = ["cli", "flight-sql", "tls-ring"]
 name = "flight"
 path = "benches/flight.rs"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-flight/gen/Cargo.toml b/arrow-flight/gen/Cargo.toml
index 2ce3f814d8..da766e75e0 100644
--- a/arrow-flight/gen/Cargo.toml
+++ b/arrow-flight/gen/Cargo.toml
@@ -34,3 +34,6 @@ publish = false
 # (and checked in) arrow.flight.protocol.rs from changing
 prost-build = { version = "0.14.1", default-features = false }
 tonic-prost-build = { version = "0.14.1", default-features = false }
+
+[lints]
+workspace = true
diff --git a/arrow-flight/gen/src/main.rs b/arrow-flight/gen/src/main.rs
index 6db70dc109..cd50214f1c 100644
--- a/arrow-flight/gen/src/main.rs
+++ b/arrow-flight/gen/src/main.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Generates the Rust bindings for the Arrow Flight protobuf definitions.
+
 use std::{
     fs::OpenOptions,
     io::{Read, Write},
diff --git a/arrow-flight/src/bin/flight_sql_client.rs 
b/arrow-flight/src/bin/flight_sql_client.rs
index 554c6339aa..c08d945b66 100644
--- a/arrow-flight/src/bin/flight_sql_client.rs
+++ b/arrow-flight/src/bin/flight_sql_client.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! A command line client for Arrow Flight SQL.
+
 use std::{sync::Arc, time::Duration};
 
 use anyhow::{Context, Result, bail};
@@ -138,7 +140,7 @@ struct ClientArgs {
     /// Since the client needs to decide on the compression before sending the 
request, there is no client<->server
     /// negotiation. If the server does NOT support the chosen compression, it 
will respond with an error a la:
     ///
-    /// ```
+    /// ```text
     /// Ipc error: Status {
     ///     code: Unimplemented,
     ///     message: "Content is compressed with `zstd` which isn't supported",
diff --git a/arrow-flight/src/encode.rs b/arrow-flight/src/encode.rs
index 810d416d9a..95fde96e37 100644
--- a/arrow-flight/src/encode.rs
+++ b/arrow-flight/src/encode.rs
@@ -463,7 +463,7 @@ impl Stream for FlightDataEncoder {
 ///
 /// For clients which may not support `DictionaryEncoding`, the 
`DictionaryHandling::Hydrate` method will bypass the process defined above
 /// and "hydrate" any `DictionaryArray` in the batch to their underlying value 
type (e.g. `TypedDictionaryArray<'_, UInt32Type, Utf8Type>` will
-/// be sent as a `StringArray`). With this method all data will be sent in 
``MessageHeader::RecordBatch` messages and the batch schema
+/// be sent as a `StringArray`). With this method all data will be sent in 
`MessageHeader::RecordBatch` messages and the batch schema
 /// will be adjusted so that all dictionary encoded fields are changed to 
fields of the dictionary value type.
 #[derive(Debug, PartialEq)]
 pub enum DictionaryHandling {
@@ -1793,7 +1793,7 @@ mod tests {
     /// Encode `batches` through a [`FlightDataEncoderBuilder`] using 
`options`, decode them
     /// again, and assert the decoded batches match the originals.
     async fn verify_flight_round_trip_with_options(
-        mut batches: Vec<RecordBatch>,
+        batches: Vec<RecordBatch>,
         options: IpcWriteOptions,
     ) {
         let expected_schema = batches.first().unwrap().schema();
@@ -1803,7 +1803,7 @@ mod tests {
             .with_dictionary_handling(DictionaryHandling::Resend)
             .build(futures::stream::iter(batches.clone().into_iter().map(Ok)));
 
-        let mut expected_batches = batches.drain(..);
+        let mut expected_batches = batches.into_iter();
 
         let mut decoder = FlightDataDecoder::new(encoder);
         while let Some(decoded) = decoder.next().await {
diff --git a/arrow-flight/src/sql/metadata/tables.rs 
b/arrow-flight/src/sql/metadata/tables.rs
index 2cd16fdc23..eedc2bcd2a 100644
--- a/arrow-flight/src/sql/metadata/tables.rs
+++ b/arrow-flight/src/sql/metadata/tables.rs
@@ -267,7 +267,7 @@ impl GetTablesBuilder {
 
     /// Return the schema of the RecordBatch that will be returned from 
[`CommandGetTables`]
     ///
-    /// Note the schema differs based on the values of `include_schema
+    /// Note the schema differs based on the values of `include_schema`
     ///
     /// [`CommandGetTables`]: crate::sql::CommandGetTables
     pub fn schema(&self) -> SchemaRef {
diff --git a/arrow-flight/tests/flight_sql_client.rs 
b/arrow-flight/tests/flight_sql_client.rs
index 97687c3dea..508a80898d 100644
--- a/arrow-flight/tests/flight_sql_client.rs
+++ b/arrow-flight/tests/flight_sql_client.rs
@@ -35,7 +35,7 @@ use arrow_flight::sql::{
 use arrow_flight::{Action, FlightData, FlightDescriptor};
 use futures::{StreamExt, TryStreamExt};
 use prost::Message;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::sync::Arc;
 use tokio::sync::Mutex;
 use tonic::{IntoStreamingRequest, Request, Status};
@@ -223,14 +223,14 @@ fn make_ingest_command() -> CommandStatementIngest {
 
 #[derive(Clone)]
 pub struct FlightSqlServiceImpl {
-    transactions: Arc<Mutex<HashMap<String, ()>>>,
+    transactions: Arc<Mutex<HashSet<String>>>,
     ingested_batches: Arc<Mutex<Vec<RecordBatch>>>,
 }
 
 impl FlightSqlServiceImpl {
     pub fn new() -> Self {
         Self {
-            transactions: Arc::new(Mutex::new(HashMap::new())),
+            transactions: Arc::new(Mutex::new(HashSet::new())),
             ingested_batches: Arc::new(Mutex::new(Vec::new())),
         }
     }
@@ -262,7 +262,7 @@ impl FlightSqlService for FlightSqlServiceImpl {
         self.transactions
             .lock()
             .await
-            .insert(transaction_id.clone(), ());
+            .insert(transaction_id.clone());
         Ok(ActionBeginTransactionResult {
             transaction_id: transaction_id.as_bytes().to_vec().into(),
         })
@@ -275,13 +275,7 @@ impl FlightSqlService for FlightSqlServiceImpl {
     ) -> Result<(), Status> {
         let transaction_id = String::from_utf8(query.transaction_id.to_vec())
             .map_err(|_| Status::invalid_argument("Invalid transaction id"))?;
-        if self
-            .transactions
-            .lock()
-            .await
-            .remove(&transaction_id)
-            .is_none()
-        {
+        if !self.transactions.lock().await.remove(&transaction_id) {
             return Err(Status::invalid_argument("Transaction id not found"));
         }
         Ok(())
diff --git a/arrow-integration-test/Cargo.toml 
b/arrow-integration-test/Cargo.toml
index 807a385744..10fa57d744 100644
--- a/arrow-integration-test/Cargo.toml
+++ b/arrow-integration-test/Cargo.toml
@@ -43,3 +43,6 @@ num-bigint = { version = "0.5", default-features = false }
 num-traits = { version = "0.2.19", default-features = false, features = 
["std"] }
 serde = { version = "1.0", default-features = false, features = ["rc", 
"derive"] }
 serde_json = { version = "1.0", default-features = false, features = ["std"] }
+
+[lints]
+workspace = true
diff --git a/arrow-integration-testing/Cargo.toml 
b/arrow-integration-testing/Cargo.toml
index cb488f5ff7..2a95cefe6a 100644
--- a/arrow-integration-testing/Cargo.toml
+++ b/arrow-integration-testing/Cargo.toml
@@ -50,3 +50,6 @@ flate2 = { version = "1", default-features = false, features 
= ["rust_backend"]
 [dev-dependencies]
 arrow-buffer = { path = "../arrow-buffer", default-features = false }
 tempfile = { version = "3", default-features = false }
+
+[lints]
+workspace = true
diff --git a/arrow-integration-testing/src/bin/arrow-file-to-stream.rs 
b/arrow-integration-testing/src/bin/arrow-file-to-stream.rs
index 661f0a047d..ca1e25ce98 100644
--- a/arrow-integration-testing/src/bin/arrow-file-to-stream.rs
+++ b/arrow-integration-testing/src/bin/arrow-file-to-stream.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Converts an Arrow IPC file to an Arrow IPC stream.
+
 // The unused_crate_dependencies lint does not work well for crates defining 
additional examples/bin targets
 #![allow(unused_crate_dependencies)]
 
diff --git a/arrow-integration-testing/src/bin/arrow-json-integration-test.rs 
b/arrow-integration-testing/src/bin/arrow-json-integration-test.rs
index 6a901cc63b..a71ba166ca 100644
--- a/arrow-integration-testing/src/bin/arrow-json-integration-test.rs
+++ b/arrow-integration-testing/src/bin/arrow-json-integration-test.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Converts between the Arrow IPC file format and the integration test JSON 
format.
+
 // The unused_crate_dependencies lint does not work well for crates defining 
additional examples/bin targets
 #![allow(unused_crate_dependencies)]
 
diff --git a/arrow-integration-testing/src/bin/arrow-stream-to-file.rs 
b/arrow-integration-testing/src/bin/arrow-stream-to-file.rs
index 8b4bb33278..ed4c289ca9 100644
--- a/arrow-integration-testing/src/bin/arrow-stream-to-file.rs
+++ b/arrow-integration-testing/src/bin/arrow-stream-to-file.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Converts an Arrow IPC stream to an Arrow IPC file.
+
 // The unused_crate_dependencies lint does not work well for crates defining 
additional examples/bin targets
 #![allow(unused_crate_dependencies)]
 
diff --git 
a/arrow-integration-testing/src/bin/flight-test-integration-client.rs 
b/arrow-integration-testing/src/bin/flight-test-integration-client.rs
index 0d16fe3b40..c23595be3b 100644
--- a/arrow-integration-testing/src/bin/flight-test-integration-client.rs
+++ b/arrow-integration-testing/src/bin/flight-test-integration-client.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! The client side of the Arrow Flight integration tests.
+
 // The unused_crate_dependencies lint does not work well for crates defining 
additional examples/bin targets
 #![allow(unused_crate_dependencies)]
 
diff --git 
a/arrow-integration-testing/src/bin/flight-test-integration-server.rs 
b/arrow-integration-testing/src/bin/flight-test-integration-server.rs
index 94be713097..87d1847afd 100644
--- a/arrow-integration-testing/src/bin/flight-test-integration-server.rs
+++ b/arrow-integration-testing/src/bin/flight-test-integration-server.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! The server side of the Arrow Flight integration tests.
+
 // The unused_crate_dependencies lint does not work well for crates defining 
additional examples/bin targets
 #![allow(unused_crate_dependencies)]
 
diff --git a/arrow-ipc/Cargo.toml b/arrow-ipc/Cargo.toml
index e8c821145b..239e8e139d 100644
--- a/arrow-ipc/Cargo.toml
+++ b/arrow-ipc/Cargo.toml
@@ -64,3 +64,6 @@ harness = false
 [[bench]]
 name = "ipc_reader"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-ipc/src/convert.rs b/arrow-ipc/src/convert.rs
index 391e73418d..6429f76f8a 100644
--- a/arrow-ipc/src/convert.rs
+++ b/arrow-ipc/src/convert.rs
@@ -190,7 +190,7 @@ impl From<crate::Field<'_>> for Field {
     }
 }
 
-/// Deserialize an ipc [crate::Schema`] from flat buffers to an arrow [Schema].
+/// Deserialize an ipc [`crate::Schema`] from flat buffers to an arrow 
[Schema].
 pub fn fb_to_schema(fb: crate::Schema) -> Schema {
     let mut fields: Vec<Field> = vec![];
     let c_fields = fb.fields().unwrap();
diff --git a/arrow-ipc/src/reader.rs b/arrow-ipc/src/reader.rs
index 05db7a8ad5..3cd11adda0 100644
--- a/arrow-ipc/src/reader.rs
+++ b/arrow-ipc/src/reader.rs
@@ -43,7 +43,7 @@ use arrow_data::{ArrayData, ArrayDataBuilder, UnsafeFlag};
 use arrow_schema::*;
 
 use crate::compression::{CompressionCodec, DecompressionContext};
-use crate::r#gen::Message::{self};
+use crate::r#gen::Message;
 use crate::{Block, CONTINUATION_MARKER, FieldNode, MetadataVersion};
 use DataType::*;
 
diff --git a/arrow-json/Cargo.toml b/arrow-json/Cargo.toml
index 4f147f572b..c740450d61 100644
--- a/arrow-json/Cargo.toml
+++ b/arrow-json/Cargo.toml
@@ -75,3 +75,6 @@ harness = false
 [[bench]]
 name = "json_writer"
 harness = false
+
+[lints]
+workspace = true
diff --git a/arrow-json/src/writer/encoder.rs b/arrow-json/src/writer/encoder.rs
index e715ca4b4e..f70f484612 100644
--- a/arrow-json/src/writer/encoder.rs
+++ b/arrow-json/src/writer/encoder.rs
@@ -242,7 +242,7 @@ pub trait EncoderFactory: std::fmt::Debug + Send + Sync {
     /// Note that the type of the field may not match the type of the array: 
for dictionary arrays unless the top-level dictionary is handled this
     /// will be called again for the keys and values of the dictionary, at 
which point the field type will still be the outer dictionary type but the
     /// array will have a different type.
-    /// For example, `field`` might have the type `Dictionary(i32, Utf8)` but 
`array` will be `Utf8`.
+    /// For example, `field` might have the type `Dictionary(i32, Utf8)` but 
`array` will be `Utf8`.
     fn make_default_encoder<'a>(
         &self,
         _field: &'a FieldRef,
diff --git a/arrow-ord/Cargo.toml b/arrow-ord/Cargo.toml
index 5c4a30994b..fa351f32d8 100644
--- a/arrow-ord/Cargo.toml
+++ b/arrow-ord/Cargo.toml
@@ -45,3 +45,6 @@ arrow-select = { workspace = true }
 [dev-dependencies]
 half = { version = "2.1", default-features = false, features = ["num-traits"] }
 rand = { version = "0.10", default-features = false, features = ["std", 
"std_rng"] }
+
+[lints]
+workspace = true
diff --git a/arrow-ord/src/sort.rs b/arrow-ord/src/sort.rs
index fbafcb6732..0c6720e8f2 100644
--- a/arrow-ord/src/sort.rs
+++ b/arrow-ord/src/sort.rs
@@ -5137,7 +5137,7 @@ mod tests {
 
         // Use standard library sort as reference
         let mut expected = test_cases.clone();
-        expected.sort();
+        expected.sort_unstable();
 
         // Use our sorting algorithm
         let string_array = StringArray::from(test_cases.clone());
@@ -5185,7 +5185,7 @@ mod tests {
 
         let strings: Vec<&str> = test_cases.iter().map(|(s, _)| *s).collect();
         let mut expected = strings.clone();
-        expected.sort();
+        expected.sort_unstable();
 
         let string_array = StringArray::from(strings.clone());
         let indices: Vec<u32> = (0..strings.len() as u32).collect();
@@ -5218,7 +5218,7 @@ mod tests {
         ];
 
         let mut expected = test_cases.clone();
-        expected.sort();
+        expected.sort_unstable();
 
         let string_array = StringArray::from(test_cases.clone());
         let indices: Vec<u32> = (0..test_cases.len() as u32).collect();
@@ -5336,7 +5336,7 @@ mod tests {
         let test_cases = vec!["a", "ab", "ba", "baa", "abba", "abbc", "abc", 
"cda"];
 
         let mut expected = test_cases.clone();
-        expected.sort();
+        expected.sort_unstable();
         expected.reverse(); // Descending order
 
         let string_array = StringArray::from(test_cases.clone());
@@ -5395,7 +5395,7 @@ mod tests {
         let limit = 3;
 
         let mut expected = test_cases.clone();
-        expected.sort();
+        expected.sort_unstable();
         expected.truncate(limit);
 
         let string_array = StringArray::from(test_cases.clone());
diff --git a/arrow-pyarrow/Cargo.toml b/arrow-pyarrow/Cargo.toml
index 9f21a9dcb0..0051de8743 100644
--- a/arrow-pyarrow/Cargo.toml
+++ b/arrow-pyarrow/Cargo.toml
@@ -40,3 +40,6 @@ arrow-array = { workspace = true, features = ["ffi"] }
 arrow-data = { workspace = true }
 arrow-schema = { workspace = true }
 pyo3 = { version = "0.29.0", default-features = false }
+
+[lints]
+workspace = true
diff --git a/arrow-row/Cargo.toml b/arrow-row/Cargo.toml
index 8293093ce4..990ae90371 100644
--- a/arrow-row/Cargo.toml
+++ b/arrow-row/Cargo.toml
@@ -48,3 +48,6 @@ arrow-cast = { workspace = true }
 arrow-ord = { workspace = true }
 arrow-select = { workspace = true }
 rand = { version = "0.9", default-features = false, features = ["std", 
"std_rng", "thread_rng"] }
+
+[lints]
+workspace = true
diff --git a/arrow-row/src/lib.rs b/arrow-row/src/lib.rs
index 05d8194932..a48f6a7bc7 100644
--- a/arrow-row/src/lib.rs
+++ b/arrow-row/src/lib.rs
@@ -4897,7 +4897,7 @@ mod tests {
         let keys_arrow_row_converter =
             
RowConverter::new(vec![SortField::new(array.key_type().clone())]).unwrap();
 
-        array.iter().enumerate().flat_map(|(index, entry)| entry.map(|entry| 
(index, Arc::clone(entry.column(0))))).for_each(|(entry_index, keys)| {
+        array.iter().enumerate().filter_map(|(index, entry)| entry.map(|entry| 
(index, Arc::clone(entry.column(0))))).for_each(|(entry_index, keys)| {
             let keys_as_rows = 
keys_arrow_row_converter.convert_columns(&[Arc::clone(&keys)]).expect("should 
be able to convert keys");
 
             for i in 0..keys_as_rows.num_rows() {
diff --git a/arrow-schema/Cargo.toml b/arrow-schema/Cargo.toml
index 2991e2aa46..e85f8850d3 100644
--- a/arrow-schema/Cargo.toml
+++ b/arrow-schema/Cargo.toml
@@ -61,3 +61,6 @@ postcard = { version = "1.0.10", default-features = false, 
features = ["use-std"
 name = "ffi"
 harness = false
 required-features = ["ffi"]
+
+[lints]
+workspace = true
diff --git a/arrow-schema/src/fields.rs b/arrow-schema/src/fields.rs
index f06d5631ed..7f6bc21172 100644
--- a/arrow-schema/src/fields.rs
+++ b/arrow-schema/src/fields.rs
@@ -196,10 +196,7 @@ impl Fields {
                 Struct(fields) => {
                     let filtered: Result<Vec<_>, _> =
                         fields.iter().map(|f| filter_field(f, 
filter)).collect();
-                    let filtered: Fields = filtered?
-                        .iter()
-                        .filter_map(|f| f.as_ref().cloned())
-                        .collect();
+                    let filtered: Fields = filtered?.iter().filter_map(|f| 
f.clone()).collect();
 
                     if filtered.is_empty() {
                         return Ok(None);
@@ -212,10 +209,8 @@ impl Fields {
                         .iter()
                         .map(|(id, f)| filter_field(f, filter).map(|f| 
f.map(|f| (id, f))))
                         .collect();
-                    let filtered: UnionFields = filtered?
-                        .iter()
-                        .filter_map(|f| f.as_ref().cloned())
-                        .collect();
+                    let filtered: UnionFields =
+                        filtered?.iter().filter_map(|f| f.clone()).collect();
 
                     if filtered.is_empty() {
                         return Ok(None);
@@ -250,10 +245,7 @@ impl Fields {
             .iter()
             .map(|f| filter_field(f, &mut filter))
             .collect();
-        let filtered = filtered?
-            .iter()
-            .filter_map(|f| f.as_ref().cloned())
-            .collect();
+        let filtered = filtered?.iter().filter_map(|f| f.clone()).collect();
         Ok(filtered)
     }
 }
diff --git a/arrow-select/Cargo.toml b/arrow-select/Cargo.toml
index a8d8056647..d6b0a7ee81 100644
--- a/arrow-select/Cargo.toml
+++ b/arrow-select/Cargo.toml
@@ -45,3 +45,6 @@ ahash = { version = "0.8", default-features = false}
 
 [dev-dependencies]
 rand = { version = "0.10", default-features = false, features = ["std", 
"std_rng", "thread_rng"] }
+
+[lints]
+workspace = true
diff --git a/arrow-select/src/filter.rs b/arrow-select/src/filter.rs
index e3ef6daa96..1c49826fe3 100644
--- a/arrow-select/src/filter.rs
+++ b/arrow-select/src/filter.rs
@@ -1806,7 +1806,7 @@ mod tests {
             .skip(offset)
             .take(truncated_length)
             .enumerate()
-            .flat_map(|(idx, v)| v.then(|| idx))
+            .filter_map(|(idx, v)| v.then_some(idx))
             .collect();
 
         assert_eq!(slice_bits, expected_bits);
@@ -2373,7 +2373,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic]
+    #[should_panic(expected = "buffer.len() >= predicate.filter.len()")]
     fn test_filter_bits_too_large() {
         let buffer = BooleanBuffer::from(vec![false; 8]);
         let predicate = BooleanArray::from(vec![true; 9]);
@@ -2382,7 +2382,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic]
+    #[should_panic(expected = "values.len() >= predicate.filter.len()")]
     fn test_filter_native_too_large() {
         let values = vec![1; 8];
         let predicate = BooleanArray::from(vec![false; 9]);
diff --git a/arrow-select/src/merge.rs b/arrow-select/src/merge.rs
index 76958e658f..2198194380 100644
--- a/arrow-select/src/merge.rs
+++ b/arrow-select/src/merge.rs
@@ -564,7 +564,10 @@ mod tests {
     }
 
     #[test]
-    #[should_panic]
+    // The message differs between debug and release: in release the
+    // `cfg(debug_assertions)` bounds check in `merge_n` is compiled out and 
the
+    // slice index panics instead.
+    #[should_panic(expected = "out of bounds")]
     fn test_merge_n_invalid_indices() {
         let a1 = StringArray::from(vec![Some("A")]);
 
diff --git a/arrow-string/Cargo.toml b/arrow-string/Cargo.toml
index 3045c355e4..7d0b20edf5 100644
--- a/arrow-string/Cargo.toml
+++ b/arrow-string/Cargo.toml
@@ -45,3 +45,6 @@ regex = { version = "1.7.0", default-features = false, 
features = ["std", "unico
 regex-syntax = { version = "0.8.0", default-features = false, features = 
["unicode"] }
 num-traits = { version = "0.2.19", default-features = false, features = 
["std"] }
 memchr = "2.7.4"
+
+[lints]
+workspace = true
diff --git a/arrow/Cargo.toml b/arrow/Cargo.toml
index 2be4cfd1f1..9dbc59fe5d 100644
--- a/arrow/Cargo.toml
+++ b/arrow/Cargo.toml
@@ -338,3 +338,6 @@ required-features = ["chrono-tz"]
 [[test]]
 name = "arithmetic"
 required-features = ["chrono-tz"]
+
+[lints]
+workspace = true
diff --git a/arrow/src/util/test_util.rs b/arrow/src/util/test_util.rs
index dbcea03ee7..aec867bb27 100644
--- a/arrow/src/util/test_util.rs
+++ b/arrow/src/util/test_util.rs
@@ -40,12 +40,9 @@ pub fn seedable_rng() -> StdRng {
 /// TODO: Originates from `parquet` utils, can be merged in [ARROW-4064]
 pub fn get_temp_file(file_name: &str, content: &[u8]) -> fs::File {
     // build tmp path to a file in "target/debug/testdata"
-    let mut path_buf = env::current_dir().unwrap();
-    path_buf.push("target");
-    path_buf.push("debug");
-    path_buf.push("testdata");
-    fs::create_dir_all(&path_buf).unwrap();
-    path_buf.push(file_name);
+    let dir = env::current_dir().unwrap().join("target/debug/testdata");
+    fs::create_dir_all(&dir).unwrap();
+    let path_buf = dir.join(file_name);
 
     // write file content
     let mut tmp_file = fs::File::create(path_buf.as_path()).unwrap();
diff --git a/arrow/tests/shrink_to_fit.rs b/arrow/tests/shrink_to_fit.rs
index 1613fefeda..564c134006 100644
--- a/arrow/tests/shrink_to_fit.rs
+++ b/arrow/tests/shrink_to_fit.rs
@@ -45,7 +45,6 @@ fn test_shrink_to_fit_after_concat() {
         memory_use(|| {
             let mut concatenated = concatenate(num_concats, 
list_array.clone());
             concatenated.shrink_to_fit(); // This is what we're testing!
-            dbg!(concatenated.data_type());
             concatenated
         });
     let expected_len = num_concats * array_len;
diff --git a/parquet-geospatial/Cargo.toml b/parquet-geospatial/Cargo.toml
index 471b355dc6..08d74ed7e9 100644
--- a/parquet-geospatial/Cargo.toml
+++ b/parquet-geospatial/Cargo.toml
@@ -41,3 +41,6 @@ wkt = { version = "0.14" }
 [lib]
 name = "parquet_geospatial"
 bench = false
+
+[lints]
+workspace = true
diff --git a/parquet-geospatial/src/bounding.rs 
b/parquet-geospatial/src/bounding.rs
index 9726c16ba4..6e59c4a953 100644
--- a/parquet-geospatial/src/bounding.rs
+++ b/parquet-geospatial/src/bounding.rs
@@ -146,7 +146,7 @@ impl GeometryBounder {
     /// for PointZ). The output is always returned sorted.
     pub fn geometry_types(&self) -> Vec<i32> {
         let mut out = self.geometry_types.iter().copied().collect::<Vec<_>>();
-        out.sort();
+        out.sort_unstable();
         out
     }
 
diff --git a/parquet-variant-compute/Cargo.toml 
b/parquet-variant-compute/Cargo.toml
index bcfb36b871..7b58fae5a2 100644
--- a/parquet-variant-compute/Cargo.toml
+++ b/parquet-variant-compute/Cargo.toml
@@ -54,3 +54,6 @@ arrow = { workspace = true, features = ["test_utils"] }
 [[bench]]
 name = "variant_kernels"
 harness = false
+
+[lints]
+workspace = true
diff --git a/parquet-variant-compute/src/lib.rs 
b/parquet-variant-compute/src/lib.rs
index 066fe15b7c..f1e87661c8 100644
--- a/parquet-variant-compute/src/lib.rs
+++ b/parquet-variant-compute/src/lib.rs
@@ -51,7 +51,7 @@ mod variant_array_builder;
 mod variant_get;
 mod variant_to_arrow;
 
-pub use variant_array::{ShreddingState, VariantArray, VariantType};
+pub use variant_array::{ShreddingState, VariantArray, VariantArrayIter, 
VariantType};
 pub use variant_array_builder::{VariantArrayBuilder, VariantValueArrayBuilder};
 
 pub use cast_to_variant::{cast_to_variant, cast_to_variant_with_options};
diff --git a/parquet-variant-compute/src/variant_get.rs 
b/parquet-variant-compute/src/variant_get.rs
index 35d94b70f4..04a2690b1e 100644
--- a/parquet-variant-compute/src/variant_get.rs
+++ b/parquet-variant-compute/src/variant_get.rs
@@ -2328,7 +2328,7 @@ mod test {
         println!("Depth 1 (shredded) passed");
     }
 
-    /// Test depth 2: Double nested field access "a.b.x" with Int32 conversion 
 
+    /// Test depth 2: Double nested field access "a.b.x" with Int32 conversion
     /// Covers shredded vs non-shredded VariantArrays for deeply nested field 
access
     #[test]
     fn test_depth_2_int32_conversion() {
diff --git a/parquet-variant-json/Cargo.toml b/parquet-variant-json/Cargo.toml
index 6ae6222da0..706446da0a 100644
--- a/parquet-variant-json/Cargo.toml
+++ b/parquet-variant-json/Cargo.toml
@@ -45,3 +45,6 @@ name = "parquet_variant_json"
 bench = false
 
 [dev-dependencies]
+
+[lints]
+workspace = true
diff --git a/parquet-variant/Cargo.toml b/parquet-variant/Cargo.toml
index c42a060794..ceb4cf2e5e 100644
--- a/parquet-variant/Cargo.toml
+++ b/parquet-variant/Cargo.toml
@@ -66,3 +66,6 @@ harness = false
 [[bench]]
 name = "variant_validation"
 harness = false
+
+[lints]
+workspace = true
diff --git a/parquet-variant/src/builder/list.rs 
b/parquet-variant/src/builder/list.rs
index 5064904ca7..4cbce2a093 100644
--- a/parquet-variant/src/builder/list.rs
+++ b/parquet-variant/src/builder/list.rs
@@ -24,7 +24,7 @@ use crate::{
 use arrow_schema::ArrowError;
 
 fn array_header(large: bool, offset_size: u8) -> u8 {
-    let large_bit = if large { 1 } else { 0 };
+    let large_bit = u8::from(large);
     (large_bit << (BASIC_TYPE_BITS + 2))
         | ((offset_size - 1) << BASIC_TYPE_BITS)
         | VariantBasicType::Array as u8
diff --git a/parquet-variant/src/utils.rs b/parquet-variant/src/utils.rs
index 61ae443d3f..33f65c4e2b 100644
--- a/parquet-variant/src/utils.rs
+++ b/parquet-variant/src/utils.rs
@@ -177,7 +177,7 @@ pub(crate) const fn expect_size_of<T>(expected: usize) {
 /// - Trailing `.` (e.g., `"foo."`)
 /// - Unclosed '[' (e.g., `"foo[1"`)
 /// - Unexpected ']' (e.g., `"foo]"`)
-/// - Trailing '`' inside bracket (treated as unclosed bracket)
+/// - Trailing `\` inside bracket (treated as unclosed bracket)
 #[inline]
 pub(crate) fn parse_path(s: &str) -> Result<Vec<VariantPathElement<'_>>, 
ArrowError> {
     let scan_field = |start: usize| {
@@ -234,7 +234,7 @@ fn parse_in_bracket(s: &str, i: usize) -> 
Result<(VariantPathElement<'_>, usize)
     let start = i + 1; // skip '['
 
     let mut unescaped = String::new();
-    let mut chars = s[start..].char_indices().peekable();
+    let mut chars = s[start..].char_indices();
     let mut end = None;
 
     while let Some((offset, c)) = chars.next() {
diff --git a/parquet/Cargo.toml b/parquet/Cargo.toml
index d34fbb5e52..4e209b52ec 100644
--- a/parquet/Cargo.toml
+++ b/parquet/Cargo.toml
@@ -319,3 +319,6 @@ harness = false
 
 [lib]
 bench = false
+
+[lints]
+workspace = true
diff --git a/parquet/benches/metadata.rs b/parquet/benches/metadata.rs
index 24ac685131..8bbc017f71 100644
--- a/parquet/benches/metadata.rs
+++ b/parquet/benches/metadata.rs
@@ -15,6 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::fmt::Write as _;
 use std::hint::black_box;
 use std::sync::Arc;
 
@@ -47,7 +48,7 @@ fn encoded_meta(is_nullable: bool, has_lists: bool, 
write_path_in_schema: bool)
     let mut column_desc_ptrs: Vec<ColumnDescPtr> = 
Vec::with_capacity(NUM_COLUMNS);
     let mut message_type = "message test_schema {".to_string();
     for i in 0..NUM_COLUMNS {
-        message_type.push_str(&format!("REQUIRED FLOAT {};", i));
+        write!(message_type, "REQUIRED FLOAT {i};").ok();
         column_desc_ptrs.push(ColumnDescPtr::new(ColumnDescriptor::new(
             Arc::new(
                 SchemaType::primitive_type_builder(&i.to_string(), 
PhysicalType::FLOAT)
diff --git a/parquet/examples/write_parquet.rs 
b/parquet/examples/write_parquet.rs
index ebdd9527b6..803f29da38 100644
--- a/parquet/examples/write_parquet.rs
+++ b/parquet/examples/write_parquet.rs
@@ -109,7 +109,7 @@ fn main() -> Result<()> {
     let mut array_builder = UInt64Builder::new();
     let mut last_log = Instant::now();
     for i in 0..args.iterations {
-        if Instant::now() - last_log > Duration::new(10, 0) {
+        if last_log.elapsed() > Duration::new(10, 0) {
             last_log = Instant::now();
             eprintln!(
                 "{} Iteration {}/{}. RSS = {}",
diff --git a/parquet/src/arrow/arrow_reader/mod.rs 
b/parquet/src/arrow/arrow_reader/mod.rs
index b41fdd111c..29ba9a4ab3 100644
--- a/parquet/src/arrow/arrow_reader/mod.rs
+++ b/parquet/src/arrow/arrow_reader/mod.rs
@@ -3693,9 +3693,7 @@ pub(crate) mod tests {
     }
 
     fn get_test_file(file_name: &str) -> File {
-        let mut path = PathBuf::new();
-        path.push(arrow::util::test_util::arrow_test_data());
-        path.push(file_name);
+        let path = 
PathBuf::from(arrow::util::test_util::arrow_test_data()).join(file_name);
 
         File::open(path.as_path()).expect("File not found!")
     }
diff --git a/parquet/src/arrow/arrow_reader/statistics.rs 
b/parquet/src/arrow/arrow_reader/statistics.rs
index 66d437243f..755d7831ca 100644
--- a/parquet/src/arrow/arrow_reader/statistics.rs
+++ b/parquet/src/arrow/arrow_reader/statistics.rs
@@ -98,7 +98,7 @@ pub(crate) fn from_bytes_to_f16(b: &[u8]) -> Option<f16> {
 macro_rules! make_stats_iterator {
     ($iterator_type:ident, $func:ident, $parquet_statistics_type:path, 
$stat_value_type:ty) => {
         /// Maps an iterator of `ParquetStatistics` into an iterator of
-        /// `&$stat_value_type``
+        /// `&$stat_value_type`
         ///
         /// Yielded elements:
         /// * Some(stats) if valid
diff --git a/parquet/src/arrow/arrow_writer/levels.rs 
b/parquet/src/arrow/arrow_writer/levels.rs
index efd77036a5..ead1ba0d9a 100644
--- a/parquet/src/arrow/arrow_writer/levels.rs
+++ b/parquet/src/arrow/arrow_writer/levels.rs
@@ -615,8 +615,8 @@ impl LevelInfoBuilder {
         nulls: Option<&NullBuffer>,
         range: Range<usize>,
     ) {
-        let offsets = &offsets[range.start..range.end];
-        let sizes = &sizes[range.start..range.end];
+        let offsets = &offsets[range.clone()];
+        let sizes = &sizes[range.clone()];
 
         let write_non_null_slice =
             |child: &mut LevelInfoBuilder, start_idx: usize, end_idx: usize| {
diff --git a/parquet/src/arrow/push_decoder/mod.rs 
b/parquet/src/arrow/push_decoder/mod.rs
index ba075b4c08..93994071fc 100644
--- a/parquet/src/arrow/push_decoder/mod.rs
+++ b/parquet/src/arrow/push_decoder/mod.rs
@@ -2396,7 +2396,7 @@ mod test {
     fn expect_needs_data<T: Debug>(
         result: Result<DecodeResult<T>, ParquetError>,
     ) -> Vec<Range<u64>> {
-        match result.expect("Expected Ok(DecodeResult::NeedsData{ranges})") {
+        match result.expect("Expected Ok(DecodeResult::NeedsData(ranges))") {
             DecodeResult::NeedsData(ranges) => ranges,
             result => panic!("Expected DecodeResult::NeedsData, got 
{result:?}"),
         }
diff --git a/parquet/src/arrow/schema/mod.rs b/parquet/src/arrow/schema/mod.rs
index f1d7ea7e88..500745c6e7 100644
--- a/parquet/src/arrow/schema/mod.rs
+++ b/parquet/src/arrow/schema/mod.rs
@@ -420,7 +420,7 @@ pub struct ArrowSchemaConverter<'a> {
     schema_root: &'a str,
     /// Should we coerce Arrow types to compatible Parquet types?
     ///
-    /// See docs on [Self::with_coerce_types]`
+    /// See docs on [`Self::with_coerce_types`]
     coerce_types: bool,
 }
 
diff --git a/parquet/src/arrow/schema/primitive.rs 
b/parquet/src/arrow/schema/primitive.rs
index c70885355d..2ca9b9b35e 100644
--- a/parquet/src/arrow/schema/primitive.rs
+++ b/parquet/src/arrow/schema/primitive.rs
@@ -183,7 +183,7 @@ fn check_decimal_length(type_length: i32) -> Result<()> {
 fn from_int32(info: &BasicTypeInfo, scale: i32, precision: i32) -> 
Result<DataType> {
     match (info.logical_type_ref(), info.converted_type()) {
         (None, ConvertedType::NONE) => Ok(DataType::Int32),
-        (Some(ref t @ LogicalType::Integer(int)), _) => match (int.bit_width, 
int.is_signed) {
+        (Some(t @ LogicalType::Integer(int)), _) => match (int.bit_width, 
int.is_signed) {
             (8, true) => Ok(DataType::Int8),
             (16, true) => Ok(DataType::Int16),
             (32, true) => Ok(DataType::Int32),
diff --git a/parquet/src/bin/parquet-fromcsv.rs 
b/parquet/src/bin/parquet-fromcsv.rs
index f2d9d24d69..37a45cf03f 100644
--- a/parquet/src/bin/parquet-fromcsv.rs
+++ b/parquet/src/bin/parquet-fromcsv.rs
@@ -41,7 +41,7 @@
 //! # Options
 //!
 //! ```text
-#![doc = include_str!("./parquet-fromcsv-help.txt")] // Update for this file : 
Run test test_command_help
+#![cfg_attr(doc, doc = include_str!("./parquet-fromcsv-help.txt"))] // Update 
for this file : Run test test_command_help
 //! ```
 //!
 //! ## Parquet file options
@@ -434,10 +434,7 @@ mod tests {
     fn test_command_help() {
         let mut cmd = Args::command();
         let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
-        let mut path_buf = PathBuf::from(dir);
-        path_buf.push("src");
-        path_buf.push("bin");
-        path_buf.push("parquet-fromcsv-help.txt");
+        let path_buf = 
PathBuf::from(dir).join("src/bin/parquet-fromcsv-help.txt");
         let expected = std::fs::read_to_string(path_buf).unwrap();
         let mut buffer_vec = Vec::new();
         let mut buffer = std::io::Cursor::new(&mut buffer_vec);
@@ -522,7 +519,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic]
+    #[should_panic(expected = "CommandLineParseError")]
     fn test_parse_arg_format_error() {
         parse_args(vec!["--input-format", "excel"]).unwrap();
     }
diff --git a/parquet/src/column/chunker/cdc.rs 
b/parquet/src/column/chunker/cdc.rs
index 3f5b6afece..2627d8921b 100644
--- a/parquet/src/column/chunker/cdc.rs
+++ b/parquet/src/column/chunker/cdc.rs
@@ -715,9 +715,7 @@ mod tests {
         let num_levels = 20;
         // def_level=1 means non-null, def_level=0 means null
         // Pattern: null at indices 0, 3, 6, 9, 12, 15, 18 → 7 nulls, 13 
non-null
-        let def_levels: Vec<i16> = (0..num_levels)
-            .map(|i| if i % 3 == 0 { 0 } else { 1 })
-            .collect();
+        let def_levels: Vec<i16> = (0..num_levels).map(|i| i16::from(i % 3 != 
0)).collect();
         let expected_non_null: usize = def_levels.iter().filter(|&&d| d == 
1).count();
 
         let chunks = chunker.calculate(
diff --git a/parquet/src/column/writer/encoder.rs 
b/parquet/src/column/writer/encoder.rs
index 094c7c26a0..9420aa40f7 100644
--- a/parquet/src/column/writer/encoder.rs
+++ b/parquet/src/column/writer/encoder.rs
@@ -69,7 +69,7 @@ pub struct DataPageValues<T> {
 }
 
 /// A generic encoder of [`ColumnValues`] to data and dictionary pages used by
-/// [super::GenericColumnWriter`]
+/// [`super::GenericColumnWriter`]
 pub trait ColumnValueEncoder {
     /// The underlying value type of [`Self::Values`]
     ///
diff --git a/parquet/src/column/writer/mod.rs b/parquet/src/column/writer/mod.rs
index d0a092a9c5..eb27af2cfb 100644
--- a/parquet/src/column/writer/mod.rs
+++ b/parquet/src/column/writer/mod.rs
@@ -4771,7 +4771,7 @@ mod tests {
             let values = 
page.iter().filter_map(Clone::clone).collect::<Vec<_>>();
             let def_levels = page
                 .iter()
-                .map(|maybe_value| if maybe_value.is_some() { 1 } else { 0 })
+                .map(|maybe_value| i16::from(maybe_value.is_some()))
                 .collect::<Vec<_>>();
             writer.write_batch(&values, Some(&def_levels), None)?;
             writer.flush_data_pages()?;
diff --git a/parquet/src/compression.rs b/parquet/src/compression.rs
index 6f3a18fe60..45b2b7edf9 100644
--- a/parquet/src/compression.rs
+++ b/parquet/src/compression.rs
@@ -20,7 +20,9 @@
 //! See [`Compression`](crate::basic::Compression) enum for all available 
compression
 //! algorithms.
 //!
-#[cfg_attr(
+// NOTE: this must be an inner attribute so that the example is attached to 
the module (and
+// therefore actually run as a doc test) rather than to the `use` statement 
below.
+#![cfg_attr(
     feature = "experimental",
     doc = r##"
 # Example
diff --git a/parquet/src/errors.rs b/parquet/src/errors.rs
index 73b4d76de5..9064ff9cf4 100644
--- a/parquet/src/errors.rs
+++ b/parquet/src/errors.rs
@@ -163,6 +163,7 @@ impl From<ParquetError> for io::Error {
 // Convenient macros for different errors
 
 macro_rules! general_err {
+    ($fmt:literal) => (ParquetError::General(format!($fmt)));
     ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
     ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, 
$($args),*)));
     ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
@@ -171,17 +172,20 @@ macro_rules! general_err {
 }
 
 macro_rules! nyi_err {
+    ($fmt:literal) => (ParquetError::NYI(format!($fmt)));
     ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
     ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, 
$($args),*)));
 }
 
 macro_rules! eof_err {
+    ($fmt:literal) => (ParquetError::EOF(format!($fmt)));
     ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
     ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, 
$($args),*)));
 }
 
 #[cfg(feature = "arrow")]
 macro_rules! arrow_err {
+    ($fmt:literal) => (ParquetError::ArrowError(format!($fmt)));
     ($fmt:expr) => (ParquetError::ArrowError($fmt.to_owned()));
     ($fmt:expr, $($args:expr),*) => (ParquetError::ArrowError(format!($fmt, 
$($args),*)));
     ($e:expr, $fmt:expr) => (ParquetError::ArrowError($fmt.to_owned(), $e));
@@ -198,3 +202,25 @@ impl From<ParquetError> for ArrowError {
         Self::ParquetError(format!("{p}"))
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// The single-argument arms of the error macros must format their 
argument, so that
+    /// inline format arguments are not silently emitted as literal text.
+    #[test]
+    fn error_macros_format_inline_args() {
+        let expected = 1;
+        let actual = 2;
+        assert_eq!(
+            general_err!("expected {expected}, got {actual}").to_string(),
+            "Parquet error: expected 1, got 2"
+        );
+        assert_eq!(
+            nyi_err!("not yet: {expected}").to_string(),
+            "NYI: not yet: 1"
+        );
+        assert_eq!(eof_err!("eof at {actual}").to_string(), "EOF: eof at 2");
+    }
+}
diff --git a/parquet/src/file/metadata/push_decoder.rs 
b/parquet/src/file/metadata/push_decoder.rs
index 7e4beb5ad9..de812b3e87 100644
--- a/parquet/src/file/metadata/push_decoder.rs
+++ b/parquet/src/file/metadata/push_decoder.rs
@@ -733,7 +733,7 @@ mod tests {
 
     /// Expect that the [`DecodeResult`] is a [`DecodeResult::NeedsData`] and 
return the corresponding ranges
     fn expect_needs_data<T: Debug>(result: Result<DecodeResult<T>>) -> 
Vec<Range<u64>> {
-        match result.expect("Expected Ok(DecodeResult::NeedsData{ranges})") {
+        match result.expect("Expected Ok(DecodeResult::NeedsData(ranges))") {
             DecodeResult::NeedsData(ranges) => ranges,
             result => panic!("Expected DecodeResult::NeedsData, got 
{result:?}"),
         }
diff --git a/parquet/src/file/metadata/reader.rs 
b/parquet/src/file/metadata/reader.rs
index d695610f20..3f0c2abeab 100644
--- a/parquet/src/file/metadata/reader.rs
+++ b/parquet/src/file/metadata/reader.rs
@@ -513,7 +513,7 @@ impl ParquetMetaDataReader {
                 remainder.slice(offset..end)
             }
             // Note: this will potentially fetch data already in remainder, 
this keeps things simple
-            _ => fetch.fetch(range.start..range.end).await?,
+            _ => fetch.fetch(range.clone()).await?,
         };
 
         // Sanity check
@@ -1209,7 +1209,6 @@ mod async_tests {
         assert_eq!(fetch_count.load(Ordering::SeqCst), 0);
         assert_eq!(suffix_fetch_count.load(Ordering::SeqCst), 2);
 
-        dbg!("test");
         // Metadata hint too large
         fetch_count.store(0, Ordering::SeqCst);
         suffix_fetch_count.store(0, Ordering::SeqCst);
diff --git a/parquet/src/file/writer.rs b/parquet/src/file/writer.rs
index 19de205be5..ddec0fdf21 100644
--- a/parquet/src/file/writer.rs
+++ b/parquet/src/file/writer.rs
@@ -1067,8 +1067,8 @@ impl<'a, W: Write> SerializedPageWriter<'a, W> {
 
     fn page_encryptor_and_sink_mut(
         &mut self,
-    ) -> Option<(&mut PageEncryptor, &mut &'a mut TrackedWrite<W>)> {
-        self.page_encryptor.as_mut().map(|pe| (pe, &mut self.sink))
+    ) -> Option<(&mut PageEncryptor, &mut TrackedWrite<W>)> {
+        self.page_encryptor.as_mut().map(|pe| (pe, &mut *self.sink))
     }
 }
 
@@ -1080,7 +1080,7 @@ impl<'a, W: Write> SerializedPageWriter<'a, W> {
 
     fn page_encryptor_and_sink_mut(
         &mut self,
-    ) -> Option<(&mut PageEncryptor, &mut &'a mut TrackedWrite<W>)> {
+    ) -> Option<(&mut PageEncryptor, &mut TrackedWrite<W>)> {
         None
     }
 }
diff --git a/parquet/src/parquet_thrift.rs b/parquet/src/parquet_thrift.rs
index 218194e0da..b8463ccc65 100644
--- a/parquet/src/parquet_thrift.rs
+++ b/parquet/src/parquet_thrift.rs
@@ -1024,7 +1024,7 @@ impl WriteThrift for String {
 /// ```
 ///
 /// which becomes in Rust
-/// ```no_run
+/// ```ignore
 /// # struct OtherStruct {}
 /// struct MyStruct {
 ///   field1: i32,
diff --git a/parquet/src/util/test_common/file_util.rs 
b/parquet/src/util/test_common/file_util.rs
index 6c031358e7..30664d6338 100644
--- a/parquet/src/util/test_common/file_util.rs
+++ b/parquet/src/util/test_common/file_util.rs
@@ -15,13 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use std::{fs, path::PathBuf, str::FromStr};
+use std::{fs, path::PathBuf};
 
 /// Returns path to the test parquet file in 'data' directory
 pub fn get_test_path(file_name: &str) -> PathBuf {
-    let mut pathbuf = 
PathBuf::from_str(&arrow::util::test_util::parquet_test_data()).unwrap();
-    pathbuf.push(file_name);
-    pathbuf
+    PathBuf::from(arrow::util::test_util::parquet_test_data()).join(file_name)
 }
 
 /// Returns file handle for a test parquet file from 'data' directory
diff --git a/parquet/tests/arrow_reader/row_filter/async.rs 
b/parquet/tests/arrow_reader/row_filter/async.rs
index fe16e426ea..059755cb7b 100644
--- a/parquet/tests/arrow_reader/row_filter/async.rs
+++ b/parquet/tests/arrow_reader/row_filter/async.rs
@@ -804,7 +804,7 @@ async fn test_multi_predicate_auto_mask_with_sparse_pages() 
{
     // filter_col: 0 for first and last 100 rows, 1 for middle 100 rows
     // value_col: just row index
     let filter_values: Vec<i32> = (0..num_rows as i32)
-        .map(|i| if (100..200).contains(&i) { 1 } else { 0 })
+        .map(|i| i32::from((100..200).contains(&i)))
         .collect();
     let value_values: Vec<i32> = (0..num_rows as i32).collect();
 
diff --git a/parquet_derive/Cargo.toml b/parquet_derive/Cargo.toml
index 81565a4d6d..0855720628 100644
--- a/parquet_derive/Cargo.toml
+++ b/parquet_derive/Cargo.toml
@@ -41,3 +41,6 @@ parquet = { workspace = true }
 
 [package.metadata.docs.rs]
 all-features = true
+
+[lints]
+workspace = true
diff --git a/parquet_derive_test/Cargo.toml b/parquet_derive_test/Cargo.toml
index 168d10891d..b7d10ab398 100644
--- a/parquet_derive_test/Cargo.toml
+++ b/parquet_derive_test/Cargo.toml
@@ -36,3 +36,6 @@ uuid = { version = "1", features = ["v4"] }
 
 [package.metadata.docs.rs]
 all-features = true
+
+[lints]
+workspace = true
diff --git a/parquet_derive_test/src/lib.rs b/parquet_derive_test/src/lib.rs
index e8462874f3..c18b1c1c49 100644
--- a/parquet_derive_test/src/lib.rs
+++ b/parquet_derive_test/src/lib.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Tests for the `parquet_derive` procedural macros.
+
 #![doc(
     html_logo_url = 
"https://raw.githubusercontent.com/apache/parquet-format/25f05e73d8cd7f5c83532ce51cb4f4de8ba5f2a2/logo/parquet-logos_1.svg";,
     html_favicon_url = 
"https://raw.githubusercontent.com/apache/parquet-format/25f05e73d8cd7f5c83532ce51cb4f4de8ba5f2a2/logo/parquet-logos_1.svg";
@@ -446,12 +448,9 @@ mod tests {
     /// Returns file handle for a temp file in 'target' directory with a 
provided content
     pub fn get_temp_file(file_name: &str, content: &[u8]) -> fs::File {
         // build tmp path to a file in "target/debug/testdata"
-        let mut path_buf = env::current_dir().unwrap();
-        path_buf.push("target");
-        path_buf.push("debug");
-        path_buf.push("testdata");
-        fs::create_dir_all(&path_buf).unwrap();
-        path_buf.push(file_name);
+        let dir = env::current_dir().unwrap().join("target/debug/testdata");
+        fs::create_dir_all(&dir).unwrap();
+        let path_buf = dir.join(file_name);
 
         // write file content
         let mut tmp_file = fs::File::create(path_buf.as_path()).unwrap();

Reply via email to