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

Jefffrey 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 684d64a580 Add `OffsetBuffer::first`/`last` to always return offset & 
remove some `unwrap`s (#10759)
684d64a580 is described below

commit 684d64a580ce2e1c6a8cf6972be278e4165db458
Author: Emil Ernerfeldt <[email protected]>
AuthorDate: Sat Aug 29 10:09:23 2026 +0200

    Add `OffsetBuffer::first`/`last` to always return offset & remove some 
`unwrap`s (#10759)
    
    # Which issue does this PR close?
    
    - Part of https://github.com/apache/arrow-rs/issues/10553
    
    # Rationale for this change
    
    This is one of four PRs splitting up the `clippy::missing_panics_doc`
    work.
    
    1. #10755 - return errors from fallible functions
    2. #10759 - remove unreachable panics
    3. #10760 - document the panics that genuinely remain
    4. #10761 - `#[expect]` the unreachable ones, so the lint can be turned
    on
    
    # What changes are included in this PR?
    Replaces `unwrap`/`expect` calls that cannot fail with non-panicking
    equivalents.
    
    # Are these changes tested?
    
    Covered by the existing tests. Every change here is a rewrite of code
    whose
    panic was unreachable, so there is no new behavior to test.
    
    # Are there any user-facing changes?
    Yes - `OffsetBuffer::last/first` no longer returns `Option`
    
    ---------
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 arrow-array/src/array/byte_array.rs                |  6 ++--
 arrow-array/src/array/byte_view_array.rs           |  5 +--
 arrow-array/src/array/list_array.rs                |  2 +-
 arrow-array/src/array/map_array.rs                 |  4 +--
 .../src/builder/generic_bytes_view_builder.rs      | 27 +++++++++-------
 .../src/builder/generic_list_view_builder.rs       |  2 +-
 arrow-array/src/types.rs                           | 10 +++---
 arrow-buffer/src/bigint/mod.rs                     | 19 ++++++++----
 arrow-buffer/src/buffer/mutable.rs                 | 18 +++++------
 arrow-buffer/src/buffer/offset.rs                  | 36 ++++++++++++++++++++++
 arrow-buffer/src/buffer/run.rs                     | 20 ++++++------
 arrow-buffer/src/builder/boolean.rs                | 18 +++++++----
 arrow-buffer/src/builder/null.rs                   | 29 ++++++++---------
 arrow-buffer/src/bytes.rs                          |  6 ++--
 arrow-buffer/src/pool.rs                           | 13 +++++++-
 arrow-cast/src/base64.rs                           |  2 +-
 arrow-cast/src/cast/list.rs                        |  2 +-
 arrow-cast/src/parse.rs                            |  2 +-
 arrow-flight/src/sql/metadata/sql_info.rs          |  7 ++---
 arrow-ipc/src/convert.rs                           | 18 +++++------
 arrow-ipc/src/reader.rs                            | 20 +++++++-----
 arrow-ipc/src/writer.rs                            | 19 +++++++-----
 arrow-row/src/lib.rs                               |  4 +--
 arrow-select/src/concat.rs                         | 10 +++---
 arrow-string/src/regexp.rs                         | 10 +++---
 parquet/src/bloom_filter/mod.rs                    |  5 +--
 parquet/src/file/metadata/footer_tail.rs           |  2 +-
 27 files changed, 186 insertions(+), 130 deletions(-)

diff --git a/arrow-array/src/array/byte_array.rs 
b/arrow-array/src/array/byte_array.rs
index 728aeb342a..bf191c325b 100644
--- a/arrow-array/src/array/byte_array.rs
+++ b/arrow-array/src/array/byte_array.rs
@@ -295,10 +295,8 @@ impl<T: ByteArrayType> GenericByteArray<T> {
 
     /// Returns true if all data within this array is ASCII
     pub fn is_ascii(&self) -> bool {
-        let offsets = self.value_offsets();
-        let start = offsets.first().unwrap();
-        let end = offsets.last().unwrap();
-        self.value_data()[start.as_usize()..end.as_usize()].is_ascii()
+        let offsets = &self.value_offsets;
+        
self.value_data()[offsets.first().as_usize()..offsets.last().as_usize()].is_ascii()
     }
 
     /// Returns the offset values in the offsets buffer
diff --git a/arrow-array/src/array/byte_view_array.rs 
b/arrow-array/src/array/byte_view_array.rs
index 0ff1a77c49..ca7abe9aea 100644
--- a/arrow-array/src/array/byte_view_array.rs
+++ b/arrow-array/src/array/byte_view_array.rs
@@ -1037,10 +1037,7 @@ where
     fn from(byte_array: &GenericByteArray<FROM>) -> Self {
         let offsets = byte_array.offsets();
 
-        let can_reuse_buffer = match offsets.last() {
-            Some(offset) => offset.as_usize() < u32::MAX as usize,
-            None => true,
-        };
+        let can_reuse_buffer = offsets.last().as_usize() < u32::MAX as usize;
 
         if can_reuse_buffer {
             // build views directly pointing to the existing buffer
diff --git a/arrow-array/src/array/list_array.rs 
b/arrow-array/src/array/list_array.rs
index ccab56db99..430750f48a 100644
--- a/arrow-array/src/array/list_array.rs
+++ b/arrow-array/src/array/list_array.rs
@@ -213,7 +213,7 @@ impl<OffsetSize: OffsetSizeTrait> 
GenericListArray<OffsetSize> {
         nulls: Option<NullBuffer>,
     ) -> Result<Self, ArrowError> {
         let len = offsets.len() - 1; // Offsets guaranteed to not be empty
-        let end_offset = offsets.last().unwrap().as_usize();
+        let end_offset = offsets.last().as_usize();
         // don't need to check other values of `offsets` because they are 
checked
         // during construction of `OffsetBuffer`
         if end_offset > values.len() {
diff --git a/arrow-array/src/array/map_array.rs 
b/arrow-array/src/array/map_array.rs
index 9c7996cab3..919619aed3 100644
--- a/arrow-array/src/array/map_array.rs
+++ b/arrow-array/src/array/map_array.rs
@@ -70,7 +70,7 @@ impl MapArray {
         ordered: bool,
     ) -> Result<Self, ArrowError> {
         let len = offsets.len() - 1; // Offsets guaranteed to not be empty
-        let end_offset = offsets.last().unwrap().as_usize();
+        let end_offset = offsets.last().as_usize();
         // don't need to check other values of `offsets` because they are 
checked
         // during construction of `OffsetBuffer`
         if end_offset > entries.len() {
@@ -259,7 +259,7 @@ impl MapArray {
         let end = *unsafe { self.value_offsets().get_unchecked(i + 1) };
         let start = *unsafe { self.value_offsets().get_unchecked(i) };
         self.entries
-            .slice(start.to_usize().unwrap(), (end - 
start).to_usize().unwrap())
+            .slice(start.as_usize(), (end - start).as_usize())
     }
 
     /// Returns ith value of this map array.
diff --git a/arrow-array/src/builder/generic_bytes_view_builder.rs 
b/arrow-array/src/builder/generic_bytes_view_builder.rs
index b68c5d2352..6ff209ef74 100644
--- a/arrow-array/src/builder/generic_bytes_view_builder.rs
+++ b/arrow-array/src/builder/generic_bytes_view_builder.rs
@@ -350,14 +350,19 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
             ArrowError::InvalidArgumentError(format!("String length {} exceeds 
u32::MAX", v.len()))
         })?;
 
-        if length <= MAX_INLINE_VIEW_LEN {
-            let mut view_buffer = [0; 16];
-            view_buffer[0..4].copy_from_slice(&length.to_le_bytes());
-            view_buffer[4..4 + v.len()].copy_from_slice(v);
-            self.views_buffer.push(u128::from_le_bytes(view_buffer));
-            self.null_buffer_builder.append_non_null();
-            return Ok(());
-        }
+        // Anything at most `MAX_INLINE_VIEW_LEN` bytes long is inlined; 
everything else
+        // needs a four byte prefix, which `first_chunk` gives us without any 
indexing.
+        let prefix = match v.first_chunk::<4>() {
+            Some(prefix) if length > MAX_INLINE_VIEW_LEN => 
u32::from_le_bytes(*prefix),
+            _ => {
+                let mut view_buffer = [0; 16];
+                view_buffer[0..4].copy_from_slice(&length.to_le_bytes());
+                view_buffer[4..4 + v.len()].copy_from_slice(v);
+                self.views_buffer.push(u128::from_le_bytes(view_buffer));
+                self.null_buffer_builder.append_non_null();
+                return Ok(());
+            }
+        };
 
         // Deduplication if:
         // (1) deduplication is enabled.
@@ -416,8 +421,7 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
 
         let view = ByteView {
             length,
-            // This won't panic as we checked the length of prefix earlier.
-            prefix: u32::from_le_bytes(v[0..4].try_into().unwrap()),
+            prefix,
             buffer_index,
             offset,
         };
@@ -702,7 +706,8 @@ pub fn make_view(data: &[u8], block_id: u32, offset: u32) 
-> u128 {
         _ => {
             let view = ByteView {
                 length: len as u32,
-                prefix: u32::from_le_bytes(data[0..4].try_into().unwrap()),
+                // this arm only matches lengths above 12, so there are at 
least four bytes
+                prefix: u32::from_le_bytes([data[0], data[1], data[2], 
data[3]]),
                 buffer_index: block_id,
                 offset,
             };
diff --git a/arrow-array/src/builder/generic_list_view_builder.rs 
b/arrow-array/src/builder/generic_list_view_builder.rs
index 925ea80940..e39cecbf65 100644
--- a/arrow-array/src/builder/generic_list_view_builder.rs
+++ b/arrow-array/src/builder/generic_list_view_builder.rs
@@ -163,7 +163,7 @@ where
     #[inline]
     pub fn append_null(&mut self) {
         self.offsets_builder.push(self.current_offset);
-        self.sizes_builder.push(OffsetSize::from_usize(0).unwrap());
+        self.sizes_builder.push(OffsetSize::zero());
         self.null_buffer_builder.append_null();
     }
 
diff --git a/arrow-array/src/types.rs b/arrow-array/src/types.rs
index 51b6b277fb..e0cc57bae5 100644
--- a/arrow-array/src/types.rs
+++ b/arrow-array/src/types.rs
@@ -963,7 +963,7 @@ impl Date32Type {
     ///
     /// Returns `Some(NaiveDate)` if it fits, `None` otherwise.
     pub fn to_naive_date_opt(i: <Date32Type as ArrowPrimitiveType>::Native) -> 
Option<NaiveDate> {
-        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
+        let epoch = NaiveDate::default();
         let d = Duration::try_days(i as i64)?;
         epoch.checked_add_signed(d)
     }
@@ -974,7 +974,7 @@ impl Date32Type {
     ///
     /// * `d` - The NaiveDate to convert
     pub fn from_naive_date(d: NaiveDate) -> <Date32Type as 
ArrowPrimitiveType>::Native {
-        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
+        let epoch = NaiveDate::default();
         d.sub(epoch).num_days() as <Date32Type as ArrowPrimitiveType>::Native
     }
 
@@ -1245,7 +1245,7 @@ impl Date64Type {
     ///
     /// Returns `Some(NaiveDateTime)` if it fits, `None` otherwise.
     pub fn to_naive_date_opt(i: <Date64Type as ArrowPrimitiveType>::Native) -> 
Option<NaiveDate> {
-        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
+        let epoch = NaiveDate::default();
         let d = Duration::try_milliseconds(i)?;
         epoch.checked_add_signed(d)
     }
@@ -1256,7 +1256,7 @@ impl Date64Type {
     ///
     /// * `d` - The NaiveDate to convert
     pub fn from_naive_date(d: NaiveDate) -> <Date64Type as 
ArrowPrimitiveType>::Native {
-        let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
+        let epoch = NaiveDate::default();
         d.sub(epoch).num_milliseconds()
     }
 
@@ -1745,7 +1745,7 @@ impl<O: OffsetSizeTrait> ByteArrayType for 
GenericBinaryType<O> {
 
     fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> 
Result<(), ArrowError> {
         // offsets are guaranteed to be monotonically increasing and non-empty
-        let max_offset = offsets.last().unwrap().as_usize();
+        let max_offset = offsets.last().as_usize();
         if values.len() < max_offset {
             return Err(ArrowError::InvalidArgumentError(format!(
                 "Maximum offset of {max_offset} is larger than values of 
length {}",
diff --git a/arrow-buffer/src/bigint/mod.rs b/arrow-buffer/src/bigint/mod.rs
index 6811e2e1ed..aa1d5d48c8 100644
--- a/arrow-buffer/src/bigint/mod.rs
+++ b/arrow-buffer/src/bigint/mod.rs
@@ -716,19 +716,26 @@ impl i256 {
             return Some(0);
         }
 
+        /// `10^32`
+        const POW10_32: i256 = 
i256::from_i128(100_000_000_000_000_000_000_000_000_000_000);
+
+        /// `10^64`
+        const POW10_64: i256 = i256::from_parts(
+            146_510_663_073_550_942_663_504_491_129_887_260_672,
+            29_387_358_770_557_187_699_218_413,
+        );
+
         // Layered approach to calculate logarithm using i128 log operations 
only
         // Consult int_log10.rs stdlib implementiation for u128
-        let pow_64: i256 = i256::from(10).checked_pow(64).unwrap();
-        let pow_32: i256 = i256::from(10).checked_pow(32).unwrap();
-        if self >= pow_64 {
-            let value = self.checked_div(pow_64)?;
+        if self >= POW10_64 {
+            let value = self.checked_div(POW10_64)?;
             // self is between 10^64 and 10^77 (~i256::MAX).
             // `value` is 14 digits max (10^77 / 10^64 = 10^13),
             // so it fits to `low` u128
             debug_assert!(value.high == 0);
             Some(64 + value.low.checked_ilog10()?)
-        } else if self >= pow_32 {
-            let value = self.checked_div(pow_32)?;
+        } else if self >= POW10_32 {
+            let value = self.checked_div(POW10_32)?;
             // self is between 10^32 and 10^64.
             // `value` is 33 digits max (10^64/10^32=10^32)
             // so it fits to `low` 128-bit value
diff --git a/arrow-buffer/src/buffer/mutable.rs 
b/arrow-buffer/src/buffer/mutable.rs
index 1dcfaf67f4..150fe44043 100644
--- a/arrow-buffer/src/buffer/mutable.rs
+++ b/arrow-buffer/src/buffer/mutable.rs
@@ -27,7 +27,7 @@ use crate::{
 };
 
 #[cfg(feature = "pool")]
-use crate::pool::{MemoryPool, MemoryReservation};
+use crate::pool::{MemoryPool, MemoryReservation, lock_reservation};
 #[cfg(feature = "pool")]
 use std::sync::Mutex;
 
@@ -238,7 +238,7 @@ impl MutableBuffer {
         let len = bytes.len();
         let data = bytes.ptr();
         #[cfg(feature = "pool")]
-        let reservation = bytes.reservation.lock().unwrap().take();
+        let reservation = lock_reservation(&bytes.reservation).take();
         mem::forget(bytes);
 
         Ok(Self {
@@ -447,7 +447,7 @@ impl MutableBuffer {
         self.layout = new_layout;
         #[cfg(feature = "pool")]
         {
-            if let Some(reservation) = 
self.reservation.lock().unwrap().as_mut() {
+            if let Some(reservation) = 
lock_reservation(&self.reservation).as_mut() {
                 reservation.resize(self.layout.size());
             }
         }
@@ -464,7 +464,7 @@ impl MutableBuffer {
         self.len = len;
         #[cfg(feature = "pool")]
         {
-            if let Some(reservation) = 
self.reservation.lock().unwrap().as_mut() {
+            if let Some(reservation) = 
lock_reservation(&self.reservation).as_mut() {
                 reservation.resize(self.len);
             }
         }
@@ -484,7 +484,7 @@ impl MutableBuffer {
         self.len = new_len;
         #[cfg(feature = "pool")]
         {
-            if let Some(reservation) = 
self.reservation.lock().unwrap().as_mut() {
+            if let Some(reservation) = 
lock_reservation(&self.reservation).as_mut() {
                 reservation.resize(self.len);
             }
         }
@@ -573,7 +573,7 @@ impl MutableBuffer {
         self.len = 0;
         #[cfg(feature = "pool")]
         {
-            if let Some(reservation) = 
self.reservation.lock().unwrap().as_mut() {
+            if let Some(reservation) = 
lock_reservation(&self.reservation).as_mut() {
                 reservation.resize(self.len);
             }
         }
@@ -608,8 +608,8 @@ impl MutableBuffer {
         let bytes = unsafe { Bytes::new(self.data, self.len, 
Deallocation::Standard(self.layout)) };
         #[cfg(feature = "pool")]
         {
-            let reservation = self.reservation.lock().unwrap().take();
-            *bytes.reservation.lock().unwrap() = reservation;
+            let reservation = lock_reservation(&self.reservation).take();
+            *lock_reservation(&bytes.reservation) = reservation;
         }
         std::mem::forget(self);
         Buffer::from(bytes)
@@ -934,7 +934,7 @@ impl MutableBuffer {
     /// multiple arrays.
     #[cfg(feature = "pool")]
     pub fn claim(&self, pool: &dyn MemoryPool) {
-        *self.reservation.lock().unwrap() = 
Some(pool.reserve(self.capacity()));
+        *lock_reservation(&self.reservation) = 
Some(pool.reserve(self.capacity()));
     }
 }
 
diff --git a/arrow-buffer/src/buffer/offset.rs 
b/arrow-buffer/src/buffer/offset.rs
index f1dcdfd5aa..12823c9eb5 100644
--- a/arrow-buffer/src/buffer/offset.rs
+++ b/arrow-buffer/src/buffer/offset.rs
@@ -177,6 +177,42 @@ impl<O: ArrowNativeType> OffsetBuffer<O> {
         Self(ScalarBuffer::from(offsets))
     }
 
+    /// The first offset, i.e. the start of the first range.
+    ///
+    /// An [`OffsetBuffer`] is never empty, so this always returns an offset.
+    ///
+    /// ```
+    /// # use arrow_buffer::OffsetBuffer;
+    /// let offsets = OffsetBuffer::<i32>::from_lengths([1, 3, 5]);
+    /// assert_eq!(offsets.first(), 0);
+    /// assert_eq!(OffsetBuffer::<i32>::new_empty().first(), 0);
+    /// ```
+    #[inline]
+    pub fn first(&self) -> O {
+        self.0
+            .first()
+            .copied()
+            .expect("An `OffsetBuffer` is never empty")
+    }
+
+    /// The last offset, i.e. the end of the last range.
+    ///
+    /// An [`OffsetBuffer`] is never empty, so this always returns an offset.
+    ///
+    /// ```
+    /// # use arrow_buffer::OffsetBuffer;
+    /// let offsets = OffsetBuffer::<i32>::from_lengths([1, 3, 5]);
+    /// assert_eq!(offsets.last(), 9);
+    /// assert_eq!(OffsetBuffer::<i32>::new_empty().last(), 0);
+    /// ```
+    #[inline]
+    pub fn last(&self) -> O {
+        self.0
+            .last()
+            .copied()
+            .expect("An `OffsetBuffer` is never empty")
+    }
+
     /// Get an Iterator over the lengths of this [`OffsetBuffer`]
     ///
     /// ```
diff --git a/arrow-buffer/src/buffer/run.rs b/arrow-buffer/src/buffer/run.rs
index c65e3b5cc6..6c9a4cb52e 100644
--- a/arrow-buffer/src/buffer/run.rs
+++ b/arrow-buffer/src/buffer/run.rs
@@ -209,8 +209,9 @@ where
             &self.run_ends[start..=end]
         };
         physical_slice.iter().map(move |&val| {
+            // `len` is at most the largest run end, so it always fits in `E`
             let val = val.as_usize().saturating_sub(offset).min(len);
-            E::from_usize(val).unwrap()
+            E::usize_as(val)
         })
     }
 
@@ -230,8 +231,8 @@ where
     ///
     /// The result is arbitrary if `logical_index >= self.len()`.
     pub fn get_physical_index(&self, logical_index: usize) -> usize {
-        let logical_index = E::usize_as(self.logical_offset + logical_index);
-        let cmp = |p: &E| p.partial_cmp(&logical_index).unwrap();
+        let logical_index = self.logical_offset + logical_index;
+        let cmp = |p: &E| p.as_usize().cmp(&logical_index);
 
         match self.run_ends.binary_search_by(cmp) {
             Ok(idx) => idx + 1,
@@ -337,16 +338,13 @@ where
 
         // Instead of sorting `logical_indices` directly, sort the 
`ordered_indices`
         // whose values are index of `logical_indices`
-        ordered_indices.sort_unstable_by(|lhs, rhs| {
-            logical_indices[*lhs]
-                .partial_cmp(&logical_indices[*rhs])
-                .unwrap()
-        });
+        ordered_indices.sort_unstable_by_key(|&idx| 
logical_indices[idx].as_usize());
 
         // Return early if all the logical indices cannot be converted to 
physical indices.
-        let largest_logical_index = 
logical_indices[*ordered_indices.last().unwrap()].as_usize();
-        if largest_logical_index >= len {
-            return Err(logical_indices[*ordered_indices.last().unwrap()]);
+        // `ordered_indices` has `indices_len` entries, and the empty case 
returned above.
+        let largest_logical_index = 
logical_indices[ordered_indices[indices_len - 1]];
+        if largest_logical_index.as_usize() >= len {
+            return Err(largest_logical_index);
         }
 
         // Skip some physical indices based on offset.
diff --git a/arrow-buffer/src/builder/boolean.rs 
b/arrow-buffer/src/builder/boolean.rs
index 3c6239e4c8..68cb2cef29 100644
--- a/arrow-buffer/src/builder/boolean.rs
+++ b/arrow-buffer/src/builder/boolean.rs
@@ -161,9 +161,11 @@ impl BooleanBufferBuilder {
         self.len = len;
 
         let remainder = self.len % 8;
-        if remainder != 0 {
+        if remainder != 0
+            && let Some(last) = self.buffer.as_mut().last_mut()
+        {
             let mask = (1_u8 << remainder).wrapping_sub(1);
-            *self.buffer.as_mut().last_mut().unwrap() &= mask;
+            *last &= mask;
         }
     }
 
@@ -248,14 +250,18 @@ impl BooleanBufferBuilder {
                 let cur_remainder = self.len % 8;
                 let new_remainder = new_len % 8;
 
-                if cur_remainder != 0 {
+                if cur_remainder != 0
+                    && let Some(last) = self.buffer.as_slice_mut().last_mut()
+                {
                     // Pad last byte with 1s
-                    *self.buffer.as_slice_mut().last_mut().unwrap() |= !((1 << 
cur_remainder) - 1)
+                    *last |= !((1 << cur_remainder) - 1);
                 }
                 self.buffer.resize(new_len_bytes, 0xFF);
-                if new_remainder != 0 {
+                if new_remainder != 0
+                    && let Some(last) = self.buffer.as_slice_mut().last_mut()
+                {
                     // Clear remaining bits
-                    *self.buffer.as_slice_mut().last_mut().unwrap() &= (1 << 
new_remainder) - 1
+                    *last &= (1 << new_remainder) - 1;
                 }
                 self.len = new_len;
             }
diff --git a/arrow-buffer/src/builder/null.rs b/arrow-buffer/src/builder/null.rs
index b1b5511010..ee58ab591e 100644
--- a/arrow-buffer/src/builder/null.rs
+++ b/arrow-buffer/src/builder/null.rs
@@ -129,16 +129,14 @@ impl NullBufferBuilder {
     /// to indicate that these `n` items are nulls.
     #[inline]
     pub fn append_n_nulls(&mut self, n: usize) {
-        self.materialize_if_needed();
-        self.bitmap_builder.as_mut().unwrap().append_n(n, false);
+        self.materialize_if_needed().append_n(n, false);
     }
 
     /// Appends a `false` into the builder
     /// to indicate that this item is null.
     #[inline]
     pub fn append_null(&mut self) {
-        self.materialize_if_needed();
-        self.bitmap_builder.as_mut().unwrap().append(false);
+        self.materialize_if_needed().append(false);
     }
 
     /// Appends a boolean value into the builder.
@@ -158,8 +156,7 @@ impl NullBufferBuilder {
     /// Panics for the same reasons as [`BooleanBufferBuilder::set_bit`]
     #[inline]
     pub fn set_bit(&mut self, index: usize, v: bool) {
-        self.materialize_if_needed();
-        self.bitmap_builder.as_mut().unwrap().set_bit(index, v);
+        self.materialize_if_needed().set_bit(index, v);
     }
 
     /// Gets a bit in the buffer at `index`
@@ -194,7 +191,7 @@ impl NullBufferBuilder {
     pub fn append_slice(&mut self, slice: &[bool]) {
         // First check if not already materialized before checking if there 
are any nulls
         if self.bitmap_builder.is_none() && slice.iter().any(|v| !v) {
-            self.materialize()
+            self.materialize_if_needed();
         }
         if let Some(buf) = self.bitmap_builder.as_mut() {
             buf.append_slice(slice)
@@ -244,19 +241,17 @@ impl NullBufferBuilder {
         Some(self.bitmap_builder.as_ref()?.as_slice())
     }
 
-    fn materialize_if_needed(&mut self) {
-        if self.bitmap_builder.is_none() {
-            self.materialize()
-        }
+    fn materialize_if_needed(&mut self) -> &mut BooleanBufferBuilder {
+        let (len, capacity) = (self.len, self.capacity);
+        self.bitmap_builder
+            .get_or_insert_with(|| Self::materialize(len, capacity))
     }
 
     #[cold]
-    fn materialize(&mut self) {
-        if self.bitmap_builder.is_none() {
-            let mut b = BooleanBufferBuilder::new(self.len.max(self.capacity));
-            b.append_n(self.len, true);
-            self.bitmap_builder = Some(b);
-        }
+    fn materialize(len: usize, capacity: usize) -> BooleanBufferBuilder {
+        let mut b = BooleanBufferBuilder::new(len.max(capacity));
+        b.append_n(len, true);
+        b
     }
 
     /// Return a mutable reference to the inner bitmap slice.
diff --git a/arrow-buffer/src/bytes.rs b/arrow-buffer/src/bytes.rs
index 07b08da43d..de9f7befe6 100644
--- a/arrow-buffer/src/bytes.rs
+++ b/arrow-buffer/src/bytes.rs
@@ -27,7 +27,7 @@ use crate::alloc::Deallocation;
 use crate::buffer::dangling_ptr;
 
 #[cfg(feature = "pool")]
-use crate::pool::{MemoryPool, MemoryReservation};
+use crate::pool::{MemoryPool, MemoryReservation, lock_reservation};
 #[cfg(feature = "pool")]
 use std::sync::Mutex;
 
@@ -110,7 +110,7 @@ impl Bytes {
     /// Register this [`Bytes`] with the provided [`MemoryPool`], replacing 
any prior reservation.
     #[cfg(feature = "pool")]
     pub(crate) fn claim(&self, pool: &dyn MemoryPool) {
-        *self.reservation.lock().unwrap() = 
Some(pool.reserve(self.capacity()));
+        *lock_reservation(&self.reservation) = 
Some(pool.reserve(self.capacity()));
     }
 
     /// Resize the memory reservation of this buffer
@@ -118,7 +118,7 @@ impl Bytes {
     /// This is a no-op if this buffer doesn't have a reservation.
     #[cfg(feature = "pool")]
     fn resize_reservation(&self, new_size: usize) {
-        let mut guard = self.reservation.lock().unwrap();
+        let mut guard = lock_reservation(&self.reservation);
         if let Some(mut reservation) = guard.take() {
             // Resize the reservation
             reservation.resize(new_size);
diff --git a/arrow-buffer/src/pool.rs b/arrow-buffer/src/pool.rs
index 95bd308a35..6acae3ffdb 100644
--- a/arrow-buffer/src/pool.rs
+++ b/arrow-buffer/src/pool.rs
@@ -30,8 +30,8 @@
 //! ```
 
 use std::fmt::Debug;
-use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
 
 /// A memory reservation within a [`MemoryPool`] that is freed on drop
 pub trait MemoryReservation: Debug + Send + Sync {
@@ -147,6 +147,17 @@ impl MemoryReservation for Tracker {
     }
 }
 
+/// Lock a memory reservation, recovering from a poisoned lock.
+///
+/// A poisoned lock only means that some other thread panicked. The 
reservation it
+/// guards is plain size accounting, so there is no broken invariant to 
protect, and
+/// recovering it is always preferable to panicking.
+pub(crate) fn lock_reservation(
+    reservation: &Mutex<Option<Box<dyn MemoryReservation>>>,
+) -> MutexGuard<'_, Option<Box<dyn MemoryReservation>>> {
+    reservation.lock().unwrap_or_else(PoisonError::into_inner)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/arrow-cast/src/base64.rs b/arrow-cast/src/base64.rs
index b444f8d1a8..0cd724df7c 100644
--- a/arrow-cast/src/base64.rs
+++ b/arrow-cast/src/base64.rs
@@ -43,7 +43,7 @@ pub fn b64_encode<E: Engine, O: OffsetSizeTrait>(
         encoded_len(len, engine.config().encode_padding()).unwrap()
     });
     let offsets = OffsetBuffer::<O>::from_lengths(lengths);
-    let buffer_len = offsets.last().unwrap().as_usize();
+    let buffer_len = offsets.last().as_usize();
     let mut buffer = vec![0_u8; buffer_len];
     let mut offset = 0;
 
diff --git a/arrow-cast/src/cast/list.rs b/arrow-cast/src/cast/list.rs
index fc07768a73..837715e885 100644
--- a/arrow-cast/src/cast/list.rs
+++ b/arrow-cast/src/cast/list.rs
@@ -326,7 +326,7 @@ pub(crate) fn cast_list<I: OffsetSizeTrait, O: 
OffsetSizeTrait>(
     let offsets = list.offsets();
     let nulls = list.nulls().cloned();
 
-    if offsets.last().unwrap().as_usize() > O::MAX_OFFSET {
+    if offsets.last().as_usize() > O::MAX_OFFSET {
         return Err(ArrowError::ComputeError(format!(
             "Offset overflow when casting from {} to {}",
             array.data_type(),
diff --git a/arrow-cast/src/parse.rs b/arrow-cast/src/parse.rs
index b6eb2692b3..c90214d467 100644
--- a/arrow-cast/src/parse.rs
+++ b/arrow-cast/src/parse.rs
@@ -185,7 +185,7 @@ pub fn string_to_datetime<T: TimeZone>(timezone: &T, s: 
&str) -> Result<DateTime
     let parser = TimestampParser::new(bytes);
     let date = parser.date().ok_or_else(|| err("error parsing date"))?;
     if bytes.len() == 10 {
-        let datetime = date.and_time(NaiveTime::from_hms_opt(0, 0, 
0).unwrap());
+        let datetime = date.and_time(NaiveTime::MIN);
         return timezone
             .from_local_datetime(&datetime)
             .single()
diff --git a/arrow-flight/src/sql/metadata/sql_info.rs 
b/arrow-flight/src/sql/metadata/sql_info.rs
index ec4f901b84..5ccf567c6b 100644
--- a/arrow-flight/src/sql/metadata/sql_info.rs
+++ b/arrow-flight/src/sql/metadata/sql_info.rs
@@ -356,11 +356,8 @@ impl SqlInfoDataBuilder {
         let mut name_builder = UInt32Builder::new();
         let mut value_builder = SqlInfoUnionBuilder::new();
 
-        let mut names: Vec<_> = self.infos.keys().copied().collect();
-        names.sort_unstable();
-
-        for key in names {
-            let (name, value) = self.infos.get_key_value(&key).unwrap();
+        // `infos` is a `BTreeMap`, so it iterates in sorted order already
+        for (name, value) in &self.infos {
             name_builder.append_value(*name);
             value_builder.append_value(value)?
         }
diff --git a/arrow-ipc/src/convert.rs b/arrow-ipc/src/convert.rs
index 586b89055d..9affcd6b4a 100644
--- a/arrow-ipc/src/convert.rs
+++ b/arrow-ipc/src/convert.rs
@@ -278,18 +278,18 @@ pub fn try_schema_from_ipc_buffer(buffer: &[u8]) -> 
Result<Schema, ArrowError> {
         ));
     }
 
-    let (len, buffer) = if buffer[..4] == CONTINUATION_MARKER {
-        if buffer.len() < 8 {
-            return Err(ArrowError::ParseError(
-                "The buffer length is less than 8 and missing the length of 
buffer".to_string(),
-            ));
-        }
-        buffer[4..].split_at(4)
+    let rest = if buffer[..4] == CONTINUATION_MARKER {
+        &buffer[4..]
     } else {
-        buffer.split_at(4)
+        buffer
+    };
+    let Some((len, buffer)) = rest.split_first_chunk::<4>() else {
+        return Err(ArrowError::ParseError(
+            "The buffer length is less than 8 and missing the length of 
buffer".to_string(),
+        ));
     };
 
-    let len = <i32>::from_le_bytes(len.try_into().unwrap());
+    let len = i32::from_le_bytes(*len);
     if len < 0 {
         return Err(ArrowError::ParseError(format!(
             "The encapsulated message's reported length is negative ({len})"
diff --git a/arrow-ipc/src/reader.rs b/arrow-ipc/src/reader.rs
index 7d757b534f..c8eb45515b 100644
--- a/arrow-ipc/src/reader.rs
+++ b/arrow-ipc/src/reader.rs
@@ -562,19 +562,23 @@ impl<'a> RecordBatchDecoder<'a> {
             // project fields
             for (idx, field) in schema.fields().iter().enumerate() {
                 // A projected field can appear more than once, so collect all 
matching positions.
-                let mut child = None;
+                let mut decoded = None;
                 for (proj_idx, projected_idx) in projection.iter().enumerate() 
{
                     if *projected_idx == idx {
-                        if child.is_none() {
-                            child = Some(self.create_array(field, &mut 
variadic_counts)?);
-                        }
-
                         // Reuse the decoded array for duplicate projection 
entries.
-                        arrays.push((proj_idx, 
child.as_ref().unwrap().clone()));
+                        let child = match decoded.clone() {
+                            Some(child) => child,
+                            None => {
+                                let child = self.create_array(field, &mut 
variadic_counts)?;
+                                decoded = Some(Arc::clone(&child));
+                                child
+                            }
+                        };
+                        arrays.push((proj_idx, child));
                     }
                 }
 
-                if child.is_none() {
+                if decoded.is_none() {
                     self.skip_field(field, &mut variadic_counts)?;
                 }
             }
@@ -949,7 +953,7 @@ pub fn read_footer_length(buf: [u8; 10]) -> Result<usize, 
ArrowError> {
     }
 
     // read footer length
-    let footer_len = i32::from_le_bytes(buf[..4].try_into().unwrap());
+    let footer_len = i32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
     footer_len
         .try_into()
         .map_err(|_| ArrowError::ParseError(format!("Invalid footer length: 
{footer_len}")))
diff --git a/arrow-ipc/src/writer.rs b/arrow-ipc/src/writer.rs
index 8f55e0fe67..11a3030e03 100644
--- a/arrow-ipc/src/writer.rs
+++ b/arrow-ipc/src/writer.rs
@@ -469,14 +469,17 @@ impl IpcWriteOptions {
         write_legacy_ipc_format: bool,
         metadata_version: crate::MetadataVersion,
     ) -> Result<Self, ArrowError> {
-        let is_alignment_valid =
-            alignment == 8 || alignment == 16 || alignment == 32 || alignment 
== 64;
-        if !is_alignment_valid {
-            return Err(ArrowError::InvalidArgumentError(
-                "Alignment should be 8, 16, 32, or 64.".to_string(),
-            ));
-        }
-        let alignment: u8 = u8::try_from(alignment).expect("range already 
checked");
+        let alignment: u8 = match alignment {
+            8 => 8,
+            16 => 16,
+            32 => 32,
+            64 => 64,
+            _ => {
+                return Err(ArrowError::InvalidArgumentError(
+                    "Alignment should be 8, 16, 32, or 64.".to_string(),
+                ));
+            }
+        };
         match metadata_version {
             crate::MetadataVersion::V1
             | crate::MetadataVersion::V2
diff --git a/arrow-row/src/lib.rs b/arrow-row/src/lib.rs
index 5f016ec7e6..284743f388 100644
--- a/arrow-row/src/lib.rs
+++ b/arrow-row/src/lib.rs
@@ -4779,7 +4779,7 @@ mod tests {
         F: FnOnce(&mut StdRng, usize) -> ArrayRef,
     {
         let offsets = OffsetBuffer::<i32>::from_lengths((0..len).map(|_| 
rng.random_range(0..10)));
-        let values_len = offsets.last().unwrap().to_usize().unwrap();
+        let values_len = offsets.last().as_usize();
         let values = values(rng, values_len);
         let nulls = NullBuffer::from_iter((0..len).map(|_| 
rng.random_bool(valid_percent)));
         let field = Arc::new(Field::new_list_field(values.data_type().clone(), 
true));
@@ -4835,7 +4835,7 @@ mod tests {
         ValuesFn: FnOnce(&mut StdRng, usize) -> ArrayRef,
     {
         let offsets = OffsetBuffer::<i32>::from_lengths((0..len).map(|_| 
rng.random_range(0..10)));
-        let entries_len = offsets.last().unwrap().to_usize().unwrap();
+        let entries_len = offsets.last().as_usize();
         let keys = gen_keys(rng, entries_len);
         let values = gen_values(rng, entries_len);
         let nulls = NullBuffer::from_iter((0..len).map(|_| 
rng.random_bool(valid_percent)));
diff --git a/arrow-select/src/concat.rs b/arrow-select/src/concat.rs
index eece5ffbaf..72dd239bbb 100644
--- a/arrow-select/src/concat.rs
+++ b/arrow-select/src/concat.rs
@@ -159,7 +159,7 @@ fn concat_lists<OffsetSize: OffsetSizeTrait>(
             output_len += l.len();
             list_has_nulls |= l.null_count() != 0;
             list_has_slices |= l.offsets()[0] > OffsetSize::zero()
-                || l.offsets().last().unwrap().as_usize() < l.values().len();
+                || l.offsets().last().as_usize() < l.values().len();
         })
         .collect::<Vec<_>>();
 
@@ -184,7 +184,7 @@ fn concat_lists<OffsetSize: OffsetSizeTrait>(
             // we concatenate them below only the relevant values are included
             let offsets = l.offsets();
             let start_offset = offsets[0].as_usize();
-            let end_offset = offsets.last().unwrap().as_usize();
+            let end_offset = offsets.last().as_usize();
             sliced_values.push(l.values().slice(start_offset, end_offset - 
start_offset));
         }
         sliced_values.iter().map(|a| a.as_ref()).collect()
@@ -224,7 +224,7 @@ fn concat_maps(
             output_len += m.len();
             map_has_nulls |= m.null_count() != 0;
             map_has_slices |=
-                m.offsets()[0] > 0 || m.offsets().last().unwrap().as_usize() < 
m.entries().len();
+                m.offsets()[0] > 0 || m.offsets().last().as_usize() < 
m.entries().len();
         })
         .collect::<Vec<_>>();
 
@@ -247,7 +247,7 @@ fn concat_maps(
         for m in &maps {
             let offsets = m.offsets();
             let start_offset = offsets[0].as_usize();
-            let end_offset = offsets.last().unwrap().as_usize();
+            let end_offset = offsets.last().as_usize();
             let entries_arr: &dyn Array = m.entries();
             sliced_entries.push(entries_arr.slice(start_offset, end_offset - 
start_offset));
         }
@@ -1042,7 +1042,7 @@ mod tests {
         // verify that this test covers the case when the first offset is 
zero, but the
         // last offset doesn't cover the entire array
         assert_eq!(list1_array.offsets()[0].as_usize(), 0);
-        assert!(list1_array.offsets().last().unwrap().as_usize() < 
list1_array.values().len());
+        assert!(list1_array.offsets().last().as_usize() < 
list1_array.values().len());
         let array_result = concat(&[&list1_array, &list2_array]).unwrap();
 
         let expected = list1_values.chain(list2);
diff --git a/arrow-string/src/regexp.rs b/arrow-string/src/regexp.rs
index 07520a2090..0474f2a7b8 100644
--- a/arrow-string/src/regexp.rs
+++ b/arrow-string/src/regexp.rs
@@ -433,14 +433,14 @@ pub fn regexp_match(
         None => (None, None),
     };
 
-    if is_flags_scalar.is_some() && is_rhs_scalar != is_flags_scalar.unwrap() {
+    if is_flags_scalar.is_some_and(|is_flags_scalar| is_rhs_scalar != 
is_flags_scalar) {
         return Err(ArrowError::ComputeError(
             "regexp_match() requires both pattern and flags to be either 
scalar or array"
                 .to_string(),
         ));
     }
 
-    if flags_array.is_some() && rhs.data_type() != flags.unwrap().data_type() {
+    if flags.is_some_and(|flags| rhs.data_type() != flags.data_type()) {
         return Err(ArrowError::ComputeError(
             "regexp_match() requires both pattern and flags to be either Utf8, 
Utf8View or LargeUtf8"
                 .to_string(),
@@ -461,7 +461,7 @@ pub fn regexp_match(
             }
         };
 
-        if regex.is_none() {
+        let Some(regex) = regex else {
             return Ok(new_null_array(
                 &DataType::List(Arc::new(Field::new_list_field(
                     array.data_type().clone(),
@@ -469,9 +469,7 @@ pub fn regexp_match(
                 ))),
                 array.len(),
             ));
-        }
-
-        let regex = regex.unwrap();
+        };
 
         let pattern = if let Some(flag) = flag {
             format!("(?{flag}){regex}")
diff --git a/parquet/src/bloom_filter/mod.rs b/parquet/src/bloom_filter/mod.rs
index 30310a3882..f92a04dd31 100644
--- a/parquet/src/bloom_filter/mod.rs
+++ b/parquet/src/bloom_filter/mod.rs
@@ -405,8 +405,9 @@ impl Sbbf {
             .chunks_exact(4 * 8)
             .map(|chunk| {
                 let mut block = Block::ZERO;
-                for (i, word) in chunk.chunks_exact(4).enumerate() {
-                    block[i] = u32::from_le_bytes(word.try_into().unwrap());
+                let (words, _remainder) = chunk.as_chunks::<4>();
+                for (i, word) in words.iter().enumerate() {
+                    block[i] = u32::from_le_bytes(*word);
                 }
                 block
             })
diff --git a/parquet/src/file/metadata/footer_tail.rs 
b/parquet/src/file/metadata/footer_tail.rs
index c33bc7a25c..41f18db70a 100644
--- a/parquet/src/file/metadata/footer_tail.rs
+++ b/parquet/src/file/metadata/footer_tail.rs
@@ -67,7 +67,7 @@ impl FooterTail {
             return Err(general_err!("Invalid Parquet file. Corrupt footer"));
         };
         // get the metadata length from the footer
-        let metadata_len = u32::from_le_bytes(slice[..4].try_into().unwrap());
+        let metadata_len = u32::from_le_bytes([slice[0], slice[1], slice[2], 
slice[3]]);
 
         Ok(FooterTail {
             // u32 won't be larger than usize in most cases

Reply via email to