Repository: jorgecarleitao/arrow2
Pull request #1161 (2022-07-13 00:03:58)

Added constructor `new_from`
Implements a more general `MutableFixedSizeListArray` constructor, `new_from`, to allow creating one with a non-nullable datatype (since `default_datatype` creates one that's nullable).

codecov[bot]: # [Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) Report
> Merging [#1161](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) (1ff6a13) into [main](https://codecov.io/gh/jorgecarleitao/arrow2/commit/91e1ef7f518d11bd5a9786b4cfb8a696d24626f4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) (91e1ef7) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##             main    #1161   +/-   ##
=======================================
  Coverage   83.61%   83.61%           
=======================================
  Files         365      365           
  Lines       35914    35911    -3     
=======================================
- Hits        30029    30027    -2     
+ Misses       5885     5884    -1     
```


| [Impacted Files](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) | Coverage Δ | |
|---|---|---|
| [src/array/fixed\_size\_list/mutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L2ZpeGVkX3NpemVfbGlzdC9tdXRhYmxlLnJz) | `52.58% <100.00%> (-1.20%)` | :arrow_down: |
| [src/bitmap/utils/slice\_iterator.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2JpdG1hcC91dGlscy9zbGljZV9pdGVyYXRvci5ycw==) | `97.56% <0.00%> (-1.22%)` | :arrow_down: |
| [src/io/ipc/read/reader.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2lvL2lwYy9yZWFkL3JlYWRlci5ycw==) | `96.32% <0.00%> (+0.33%)` | :arrow_up: |
| [src/bitmap/immutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2JpdG1hcC9pbW11dGFibGUucnM=) | `84.56% <0.00%> (+0.61%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao). Last update [91e1ef7...1ff6a13](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1161?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao).


Patch:
diff --git a/examples/avro_kafka.rs b/examples/avro_kafka.rs
index 0ee461a5b7..5fb392fd93 100644
--- a/examples/avro_kafka.rs
+++ b/examples/avro_kafka.rs
@@ -4,7 +4,7 @@ use arrow2::{
     io::avro,
 };
 
-fn read_schema_id<R: std::io::Read>(reader: &mut R) -> Result<i32, Error> {
+fn read_schema_id<R: std::io::Read>(reader: &mut R) -> Result<u32, Error> {
     let mut header = [0; 5];
     reader.read_exact(&mut header)?;
 
@@ -13,7 +13,7 @@ fn read_schema_id<R: std::io::Read>(reader: &mut R) -> Result<i32, Error> {
             "Avro requires the first byte to be a zero".to_string(),
         ));
     }
-    Ok(i32::from_be_bytes(header[1..].try_into().unwrap()))
+    Ok(u32::from_be_bytes(header[1..].try_into().unwrap()))
 }
 
 fn read_block<R: std::io::Read>(reader: &mut R, block: &mut avro::Block) -> Result<(), Error> {
diff --git a/src/array/fixed_size_list/mutable.rs b/src/array/fixed_size_list/mutable.rs
index 1ffcd15c4d..5798e4472e 100644
--- a/src/array/fixed_size_list/mutable.rs
+++ b/src/array/fixed_size_list/mutable.rs
@@ -32,13 +32,7 @@ impl<M: MutableArray> MutableFixedSizeListArray<M> {
     /// Creates a new [`MutableFixedSizeListArray`] from a [`MutableArray`] and size.
     pub fn new(values: M, size: usize) -> Self {
         let data_type = FixedSizeListArray::default_datatype(values.data_type().clone(), size);
-        assert_eq!(values.len(), 0);
-        Self {
-            size,
-            data_type,
-            values,
-            validity: None,
-        }
+        Self::new_from(values, data_type, size)
     }
 
     /// Creates a new [`MutableFixedSizeListArray`] from a [`MutableArray`] and size.
@@ -47,7 +41,16 @@ impl<M: MutableArray> MutableFixedSizeListArray<M> {
             Box::new(Field::new(name, values.data_type().clone(), nullable)),
             size,
         );
+        Self::new_from(values, data_type, size)
+    }
+
+    /// Creates a new [`MutableFixedSizeListArray`] from a [`MutableArray`], [`DataType`] and size.
+    pub fn new_from(values: M, data_type: DataType, size: usize) -> Self {
         assert_eq!(values.len(), 0);
+        match data_type {
+            DataType::FixedSizeList(..) => (),
+            _ => panic!("data type must be FixedSizeList (got {:?})", data_type),
+        };
         Self {
             size,
             data_type,
diff --git a/src/buffer/immutable.rs b/src/buffer/immutable.rs
index 6abae156a9..57d8ce2134 100644
--- a/src/buffer/immutable.rs
+++ b/src/buffer/immutable.rs
@@ -2,14 +2,13 @@ use std::{iter::FromIterator, ops::Deref, sync::Arc, usize};
 
 use super::Bytes;
 
-/// [`Buffer`] is a contiguous memory region of plain old data types
-/// that can be shared across thread boundaries.
+/// [`Buffer`] is a contiguous memory region that can be shared across
+/// thread boundaries.
 ///
 /// The easiest way to think about [`Buffer<T>`] is being equivalent to
 /// a `Arc<Vec<T>>`, with the following differences:
-/// * `T` must be [`NativeType`]
 /// * slicing and cloning is `O(1)`.
-/// * it supports external allocated memory (via FFI)
+/// * it supports external allocated memory
 ///
 /// The easiest way to create one is to use its implementation of `From<Vec<T>>`.
 ///
diff --git a/src/compute/boolean.rs b/src/compute/boolean.rs
index 39084400f9..46d7266954 100644
--- a/src/compute/boolean.rs
+++ b/src/compute/boolean.rs
@@ -2,21 +2,20 @@
 use crate::array::{Array, BooleanArray};
 use crate::bitmap::{Bitmap, MutableBitmap};
 use crate::datatypes::DataType;
-use crate::error::{Error, Result};
 use crate::scalar::BooleanScalar;
 
 use super::utils::combine_validities;
 
 /// Helper function to implement binary kernels
-fn binary_boolean_kernel<F>(lhs: &BooleanArray, rhs: &BooleanArray, op: F) -> Result<BooleanArray>
+fn binary_boolean_kernel<F>(lhs: &BooleanArray, rhs: &BooleanArray, op: F) -> BooleanArray
 where
     F: Fn(&Bitmap, &Bitmap) -> Bitmap,
 {
-    if lhs.len() != rhs.len() {
-        return Err(Error::InvalidArgumentError(
-            "Cannot perform bitwise operation on arrays of different length".to_string(),
-        ));
-    }
+    assert_eq!(
+        lhs.len(),
+        rhs.len(),
+        "lhs and rhs must have the same length"
+    );
 
     let validity = combine_validities(lhs.validity(), rhs.validity());
 
@@ -25,48 +24,40 @@ where
 
     let values = op(left_buffer, right_buffer);
 
-    Ok(BooleanArray::new(DataType::Boolean, values, validity))
+    BooleanArray::new(DataType::Boolean, values, validity)
 }
 
-/// Performs `AND` operation on two arrays. If either left or right value is null then the
-/// result is also null.
-/// # Error
-/// This function errors when the arrays have different lengths.
-/// # Example
+/// Performs `&&` operation on two [`BooleanArray`], combining the validities.
+/// # Panics
+/// This function panics iff the arrays have different lengths.
+/// # Examples
 /// ```rust
 /// use arrow2::array::BooleanArray;
-/// use arrow2::error::Result;
 /// use arrow2::compute::boolean::and;
-/// # fn main() -> Result<()> {
+///
 /// let a = BooleanArray::from(&[Some(false), Some(true), None]);
 /// let b = BooleanArray::from(&[Some(true), Some(true), Some(false)]);
-/// let and_ab = and(&a, &b)?;
+/// let and_ab = and(&a, &b);
 /// assert_eq!(and_ab, BooleanArray::from(&[Some(false), Some(true), None]));
-/// # Ok(())
-/// # }
 /// ```
-pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
+pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
     binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs & rhs)
 }
 
-/// Performs `OR` operation on two arrays. If either left or right value is null then the
-/// result is also null.
-/// # Error
-/// This function errors when the arrays have different lengths.
-/// # Example
+/// Performs `||` operation on two [`BooleanArray`], combining the validities.
+/// # Panics
+/// This function panics iff the arrays have different lengths.
+/// # Examples
 /// ```rust
 /// use arrow2::array::BooleanArray;
-/// use arrow2::error::Result;
 /// use arrow2::compute::boolean::or;
-/// # fn main() -> Result<()> {
+///
 /// let a = BooleanArray::from(vec![Some(false), Some(true), None]);
 /// let b = BooleanArray::from(vec![Some(true), Some(true), Some(false)]);
-/// let or_ab = or(&a, &b)?;
+/// let or_ab = or(&a, &b);
 /// assert_eq!(or_ab, BooleanArray::from(vec![Some(true), Some(true), None]));
-/// # Ok(())
-/// # }
 /// ```
-pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
+pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
     binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs | rhs)
 }
 
@@ -76,11 +67,10 @@ pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
 /// ```rust
 /// use arrow2::array::BooleanArray;
 /// use arrow2::compute::boolean::not;
-/// # fn main() {
+///
 /// let a = BooleanArray::from(vec![Some(false), Some(true), None]);
 /// let not_a = not(&a);
 /// assert_eq!(not_a, BooleanArray::from(vec![Some(true), Some(false), None]));
-/// # }
 /// ```
 pub fn not(array: &BooleanArray) -> BooleanArray {
     let values = !array.values();
@@ -88,9 +78,7 @@ pub fn not(array: &BooleanArray) -> BooleanArray {
     BooleanArray::new(DataType::Boolean, values, validity)
 }
 
-/// Returns a non-null [BooleanArray] with whether each value of the array is null.
-/// # Error
-/// This function never errors.
+/// Returns a non-null [`BooleanArray`] with whether each value of the array is null.
 /// # Example
 /// ```rust
 /// use arrow2::array::BooleanArray;
@@ -112,16 +100,15 @@ pub fn is_null(input: &dyn Array) -> BooleanArray {
     BooleanArray::new(DataType::Boolean, values, None)
 }
 
-/// Returns a non-null [BooleanArray] with whether each value of the array is not null.
+/// Returns a non-null [`BooleanArray`] with whether each value of the array is not null.
 /// # Example
 /// ```rust
 /// use arrow2::array::BooleanArray;
 /// use arrow2::compute::boolean::is_not_null;
-/// # fn main() {
+///
 /// let a = BooleanArray::from(&vec![Some(false), Some(true), None]);
 /// let a_is_not_null = is_not_null(&a);
 /// assert_eq!(a_is_not_null, BooleanArray::from_slice(&vec![true, true, false]));
-/// # }
 /// ```
 pub fn is_not_null(input: &dyn Array) -> BooleanArray {
     let values = match input.validity() {
@@ -142,12 +129,12 @@ pub fn is_not_null(input: &dyn Array) -> BooleanArray {
 /// use arrow2::array::BooleanArray;
 /// use arrow2::compute::boolean::and_scalar;
 /// use arrow2::scalar::BooleanScalar;
-/// # fn main() {
+///
 /// let array = BooleanArray::from_slice(&[false, false, true, true]);
 /// let scalar = BooleanScalar::new(Some(true));
 /// let result = and_scalar(&array, &scalar);
 /// assert_eq!(result, BooleanArray::from_slice(&[false, false, true, true]));
-/// # }
+///
 /// ```
 pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
     match scalar.value() {
@@ -186,7 +173,7 @@ pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
     }
 }
 
-/// Check if any of the values in the array is `true`
+/// Returns whether any of the values in the array is `true`
 pub fn any(array: &BooleanArray) -> bool {
     if array.is_empty() {
         false
diff --git a/src/compute/boolean_kleene.rs b/src/compute/boolean_kleene.rs
index 7bd412bfce..48d90433ee 100644
--- a/src/compute/boolean_kleene.rs
+++ b/src/compute/boolean_kleene.rs
@@ -1,35 +1,31 @@
 //! Boolean operators of [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics).
 use crate::datatypes::DataType;
-use crate::error::{Error, Result};
 use crate::scalar::BooleanScalar;
 use crate::{
-    array::BooleanArray,
+    array::{Array, BooleanArray},
     bitmap::{binary, quaternary, ternary, unary, Bitmap, MutableBitmap},
 };
 
 /// Logical 'or' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)
-/// # Errors
-/// This function errors if the operands have different lengths.
+/// # Panics
+/// This function panics iff the arrays have a different length
 /// # Example
 ///
 /// ```rust
-/// # use arrow2::error::Result;
 /// use arrow2::array::BooleanArray;
 /// use arrow2::compute::boolean_kleene::or;
-/// # fn main() -> Result<()> {
+///
 /// let a = BooleanArray::from(&[Some(true), Some(false), None]);
 /// let b = BooleanArray::from(&[None, None, None]);
-/// let or_ab = or(&a, &b)?;
+/// let or_ab = or(&a, &b);
 /// assert_eq!(or_ab, BooleanArray::from(&[Some(true), None, None]));
-/// # Ok(())
-/// # }
 /// ```
-pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
-    if lhs.len() != rhs.len() {
-        return Err(Error::InvalidArgumentError(
-            "Cannot perform bitwise operation on arrays of different length".to_string(),
-        ));
-    }
+pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
+    assert_eq!(
+        lhs.len(),
+        rhs.len(),
+        "lhs and rhs must have the same length"
+    );
 
     let lhs_values = lhs.values();
     let rhs_values = rhs.values();
@@ -90,36 +86,29 @@ pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
         }
         (None, None) => None,
     };
-    Ok(BooleanArray::new(
-        DataType::Boolean,
-        lhs_values | rhs_values,
-        validity,
-    ))
+    BooleanArray::new(DataType::Boolean, lhs_values | rhs_values, validity)
 }
 
 /// Logical 'and' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)
-/// # Errors
-/// This function errors if the operands have different lengths.
+/// # Panics
+/// This function panics iff the arrays have a different length
 /// # Example
 ///
 /// ```rust
-/// # use arrow2::error::Result;
 /// use arrow2::array::BooleanArray;
 /// use arrow2::compute::boolean_kleene::and;
-/// # fn main() -> Result<()> {
+///
 /// let a = BooleanArray::from(&[Some(true), Some(false), None]);
 /// let b = BooleanArray::from(&[None, None, None]);
-/// let and_ab = and(&a, &b)?;
+/// let and_ab = and(&a, &b);
 /// assert_eq!(and_ab, BooleanArray::from(&[None, Some(false), None]));
-/// # Ok(())
-/// # }
 /// ```
-pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
-    if lhs.len() != rhs.len() {
-        return Err(Error::InvalidArgumentError(
-            "Cannot perform bitwise operation on arrays of different length".to_string(),
-        ));
-    }
+pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
+    assert_eq!(
+        lhs.len(),
+        rhs.len(),
+        "lhs and rhs must have the same length"
+    );
 
     let lhs_values = lhs.values();
     let rhs_values = rhs.values();
@@ -179,11 +168,7 @@ pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
         }
         (None, None) => None,
     };
-    Ok(BooleanArray::new(
-        DataType::Boolean,
-        lhs_values & rhs_values,
-        validity,
-    ))
+    BooleanArray::new(DataType::Boolean, lhs_values & rhs_values, validity)
 }
 
 /// Logical 'or' operation on an array and a scalar value with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)
@@ -193,12 +178,11 @@ pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result<BooleanArray> {
 /// use arrow2::array::BooleanArray;
 /// use arrow2::scalar::BooleanScalar;
 /// use arrow2::compute::boolean_kleene::or_scalar;
-/// # fn main() {
+///
 /// let array = BooleanArray::from(&[Some(true), Some(false), None]);
 /// let scalar = BooleanScalar::new(Some(false));
 /// let result = or_scalar(&array, &scalar);
 /// assert_eq!(result, BooleanArray::from(&[Some(true), Some(false), None]));
-/// # }
 /// ```
 pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
     match scalar.value() {
@@ -226,12 +210,11 @@ pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
 /// use arrow2::array::BooleanArray;
 /// use arrow2::scalar::BooleanScalar;
 /// use arrow2::compute::boolean_kleene::and_scalar;
-/// # fn main() {
+///
 /// let array = BooleanArray::from(&[Some(true), Some(false), None]);
 /// let scalar = BooleanScalar::new(None);
 /// let result = and_scalar(&array, &scalar);
 /// assert_eq!(result, BooleanArray::from(&[None, Some(false), None]));
-/// # }
 /// ```
 pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
     match scalar.value() {
@@ -250,3 +233,25 @@ pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray
         }
     }
 }
+
+/// Returns whether any of the values in the array is `true`
+pub fn any(array: &BooleanArray) -> bool {
+    if array.is_empty() {
+        false
+    } else if array.validity().is_some() {
+        array.into_iter().any(|v| v == Some(true))
+    } else {
+        let vals = array.values();
+        vals.unset_bits() != vals.len()
+    }
+}
+
+/// Returns whether all values in the array are `true`
+pub fn all(array: &BooleanArray) -> bool {
+    if array.is_empty() || array.null_count() > 0 {
+        false
+    } else {
+        let vals = array.values();
+        vals.unset_bits() == 0
+    }
+}
diff --git a/src/compute/comparison/mod.rs b/src/compute/comparison/mod.rs
index 8f67856b90..4ad7920705 100644
--- a/src/compute/comparison/mod.rs
+++ b/src/compute/comparison/mod.rs
@@ -515,21 +515,20 @@ fn finish_eq_validities(
         (Some(lhs), None) => compute::boolean::and(
             &BooleanArray::new(DataType::Boolean, lhs, None),
             &output_without_validities,
-        )
-        .unwrap(),
+        ),
         (None, Some(rhs)) => compute::boolean::and(
             &output_without_validities,
             &BooleanArray::new(DataType::Boolean, rhs, None),
-        )
-        .unwrap(),
+        ),
         (Some(lhs), Some(rhs)) => {
             let lhs = BooleanArray::new(DataType::Boolean, lhs, None);
             let rhs = BooleanArray::new(DataType::Boolean, rhs, None);
             let eq_validities = compute::comparison::boolean::eq(&lhs, &rhs);
-            compute::boolean::and(&output_without_validities, &eq_validities).unwrap()
+            compute::boolean::and(&output_without_validities, &eq_validities)
         }
     }
 }
+
 fn finish_neq_validities(
     output_without_validities: BooleanArray,
     validity_lhs: Option<Bitmap>,
@@ -540,18 +539,18 @@ fn finish_neq_validities(
         (Some(lhs), None) => {
             let lhs_negated =
                 compute::boolean::not(&BooleanArray::new(DataType::Boolean, lhs, None));
-            compute::boolean::or(&lhs_negated, &output_without_validities).unwrap()
+            compute::boolean::or(&lhs_negated, &output_without_validities)
         }
         (None, Some(rhs)) => {
             let rhs_negated =
                 compute::boolean::not(&BooleanArray::new(DataType::Boolean, rhs, None));
-            compute::boolean::or(&output_without_validities, &rhs_negated).unwrap()
+            compute::boolean::or(&output_without_validities, &rhs_negated)
         }
         (Some(lhs), Some(rhs)) => {
             let lhs = BooleanArray::new(DataType::Boolean, lhs, None);
             let rhs = BooleanArray::new(DataType::Boolean, rhs, None);
             let neq_validities = compute::comparison::boolean::neq(&lhs, &rhs);
-            compute::boolean::or(&output_without_validities, &neq_validities).unwrap()
+            compute::boolean::or(&output_without_validities, &neq_validities)
         }
     }
 }
diff --git a/src/compute/filter.rs b/src/compute/filter.rs
index 4bcb2be744..e2b19f0c7d 100644
--- a/src/compute/filter.rs
+++ b/src/compute/filter.rs
@@ -267,7 +267,7 @@ pub fn filter(array: &dyn Array, filter: &BooleanArray) -> Result<Box<dyn Array>
     let false_count = filter.values().unset_bits();
     if false_count == filter.len() {
         assert_eq!(array.len(), filter.len());
-        return Ok(array.slice(0, 0));
+        return Ok(new_empty_array(array.data_type().clone()));
     }
     if false_count == 0 {
         assert_eq!(array.len(), filter.len());
diff --git a/src/io/flight/mod.rs b/src/io/flight/mod.rs
index 59ba0a83d8..4072c0d0d0 100644
--- a/src/io/flight/mod.rs
+++ b/src/io/flight/mod.rs
@@ -24,11 +24,11 @@ pub use crate::io::ipc::write::common::WriteOptions;
 /// # Errors
 /// This function errors iff `fields` is not consistent with `columns`
 pub fn serialize_batch(
-    columns: &Chunk<Box<dyn Array>>,
+    chunk: &Chunk<Box<dyn Array>>,
     fields: &[IpcField],
     options: &WriteOptions,
 ) -> Result<(Vec<FlightData>, FlightData)> {
-    if fields.len() != columns.arrays().len() {
+    if fields.len() != chunk.arrays().len() {
         return Err(Error::InvalidArgumentError("The argument `fields` must be consistent with the columns' schema. Use e.g. &arrow2::io::flight::default_ipc_fields(&schema.fields)".to_string()));
     }
 
@@ -38,7 +38,7 @@ pub fn serialize_batch(
     };
 
     let (encoded_dictionaries, encoded_batch) =
-        encode_chunk(columns, fields, &mut dictionary_tracker, options)
+        encode_chunk(chunk, fields, &mut dictionary_tracker, options)
             .expect("DictionaryTracker configured above to not error on replacement");
 
     let flight_dictionaries = encoded_dictionaries.into_iter().map(Into::into).collect();
@@ -63,15 +63,14 @@ pub fn serialize_schema_to_result(
     ipc_fields: Option<&[IpcField]>,
 ) -> SchemaResult {
     SchemaResult {
-        schema: schema_as_flatbuffer(schema, ipc_fields),
+        schema: _serialize_schema(schema, ipc_fields),
     }
 }
 
 /// Serializes a [`Schema`] to [`FlightData`].
 pub fn serialize_schema(schema: &Schema, ipc_fields: Option<&[IpcField]>) -> FlightData {
-    let data_header = schema_as_flatbuffer(schema, ipc_fields);
     FlightData {
-        data_header,
+        data_header: _serialize_schema(schema, ipc_fields),
         ..Default::default()
     }
 }
@@ -93,7 +92,7 @@ pub fn serialize_schema_to_info(
     Ok(schema)
 }
 
-fn schema_as_flatbuffer(schema: &Schema, ipc_fields: Option<&[IpcField]>) -> Vec<u8> {
+fn _serialize_schema(schema: &Schema, ipc_fields: Option<&[IpcField]>) -> Vec<u8> {
     if let Some(ipc_fields) = ipc_fields {
         write::schema_to_bytes(schema, ipc_fields)
     } else {
diff --git a/src/io/ipc/read/common.rs b/src/io/ipc/read/common.rs
index 5638a5289e..306df0061c 100644
--- a/src/io/ipc/read/common.rs
+++ b/src/io/ipc/read/common.rs
@@ -226,8 +226,8 @@ fn first_dict_field<'a>(
     Err(Error::from(OutOfSpecKind::InvalidId { requested_id: id }))
 }
 
-/// Read the dictionary from the buffer and provided metadata,
-/// updating the `dictionaries` with the resulting dictionary
+/// Reads a dictionary from the reader,
+/// updating `dictionaries` with the resulting dictionary
 #[allow(clippy::too_many_arguments)]
 pub fn read_dictionary<R: Read + Seek>(
     batch: arrow_format::ipc::DictionaryBatchRef,
@@ -269,7 +269,7 @@ pub fn read_dictionary<R: Read + Seek>(
                 fields: vec![first_ipc_field.clone()],
                 is_little_endian: ipc_schema.is_little_endian,
             };
-            let columns = read_record_batch(
+            let chunk = read_record_batch(
                 batch,
                 &fields,
                 &ipc_schema,
@@ -282,8 +282,7 @@ pub fn read_dictionary<R: Read + Seek>(
                 file_size,
                 scratch,
             )?;
-            let mut arrays = columns.into_arrays();
-            arrays.pop().unwrap()
+            chunk.into_arrays().pop().unwrap()
         }
         _ => {
             return Err(Error::from(OutOfSpecKind::InvalidIdDataType {
diff --git a/src/io/ipc/read/schema.rs b/src/io/ipc/read/schema.rs
index b54292baab..7f970786aa 100644
--- a/src/io/ipc/read/schema.rs
+++ b/src/io/ipc/read/schema.rs
@@ -328,17 +328,16 @@ fn get_data_type(
 }
 
 /// Deserialize an flatbuffers-encoded Schema message into [`Schema`] and [`IpcSchema`].
-pub fn deserialize_schema(bytes: &[u8]) -> Result<(Schema, IpcSchema)> {
-    let message = arrow_format::ipc::MessageRef::read_as_root(bytes)
+pub fn deserialize_schema(message: &[u8]) -> Result<(Schema, IpcSchema)> {
+    let message = arrow_format::ipc::MessageRef::read_as_root(message)
         .map_err(|err| Error::oos(format!("Unable deserialize message: {:?}", err)))?;
 
-    let schema = match message.header()?.ok_or_else(|| {
-        Error::oos("Unable to convert flight data header to a record batch".to_string())
-    })? {
+    let schema = match message
+        .header()?
+        .ok_or_else(|| Error::oos("Unable to convert header to a schema".to_string()))?
+    {
         arrow_format::ipc::MessageHeaderRef::Schema(schema) => Ok(schema),
-        _ => Err(Error::nyi(
-            "flight currently only supports reading RecordBatch messages",
-        )),
+        _ => Err(Error::nyi("The message is expected to be a Schema message")),
     }?;
 
     fb_to_schema(schema)
diff --git a/src/io/parquet/read/deserialize/simple.rs b/src/io/parquet/read/deserialize/simple.rs
index e9257d045e..8f75ea6ad9 100644
--- a/src/io/parquet/read/deserialize/simple.rs
+++ b/src/io/parquet/read/deserialize/simple.rs
@@ -279,6 +279,37 @@ pub fn page_iter_to_arrays<'a, I: 'a + DataPages>(
     })
 }
 
+/// Unify the timestamp unit from parquet TimeUnit into arrow's TimeUnit
+/// Returns (a int64 factor, is_multiplier)
+fn unifiy_timestmap_unit(
+    logical_type: &Option<PrimitiveLogicalType>,
+    time_unit: TimeUnit,
+) -> (i64, bool) {
+    if let Some(PrimitiveLogicalType::Timestamp { unit, .. }) = logical_type {
+        match (*unit, time_unit) {
+            (ParquetTimeUnit::Milliseconds, TimeUnit::Millisecond)
+            | (ParquetTimeUnit::Microseconds, TimeUnit::Microsecond)
+            | (ParquetTimeUnit::Nanoseconds, TimeUnit::Nanosecond) => (1, true),
+
+            (ParquetTimeUnit::Milliseconds, TimeUnit::Second)
+            | (ParquetTimeUnit::Microseconds, TimeUnit::Millisecond)
+            | (ParquetTimeUnit::Nanoseconds, TimeUnit::Microsecond) => (1000, false),
+
+            (ParquetTimeUnit::Microseconds, TimeUnit::Second)
+            | (ParquetTimeUnit::Nanoseconds, TimeUnit::Millisecond) => (1_000_000, false),
+
+            (ParquetTimeUnit::Nanoseconds, TimeUnit::Second) => (1_000_000_000, false),
+
+            (ParquetTimeUnit::Milliseconds, TimeUnit::Microsecond)
+            | (ParquetTimeUnit::Microseconds, TimeUnit::Nanosecond) => (1_000, true),
+
+            (ParquetTimeUnit::Milliseconds, TimeUnit::Nanosecond) => (1_000_000, true),
+        }
+    } else {
+        (1, true)
+    }
+}
+
 fn timestamp<'a, I: 'a + DataPages>(
     pages: I,
     physical_type: &PhysicalType,
@@ -288,17 +319,16 @@ fn timestamp<'a, I: 'a + DataPages>(
     time_unit: TimeUnit,
 ) -> Result<ArrayIter<'a>> {
     if physical_type == &PhysicalType::Int96 {
-        if time_unit == TimeUnit::Nanosecond {
-            return Ok(dyn_iter(iden(primitive::Iter::new(
-                pages,
-                data_type,
-                chunk_size,
-                int96_to_i64_ns,
-            ))));
-        } else {
-            return Err(Error::nyi("Can't decode int96 to timestamp other than ns"));
-        }
+        let iter = primitive::Iter::new(pages, data_type, chunk_size, int96_to_i64_ns);
+
+        let (factor, is_multiplier) = unifiy_timestmap_unit(logical_type, time_unit);
+        return match (factor, is_multiplier) {
+            (1, _) => Ok(dyn_iter(iden(iter))),
+            (a, true) => Ok(dyn_iter(op(iter, move |x| x * a))),
+            (a, false) => Ok(dyn_iter(op(iter, move |x| x / a))),
+        };
     };
+
     if physical_type != &PhysicalType::Int64 {
         return Err(Error::nyi(
             "Can't decode a timestamp from a non-int64 parquet type",
@@ -306,36 +336,12 @@ fn timestamp<'a, I: 'a + DataPages>(
     }
 
     let iter = primitive::Iter::new(pages, data_type, chunk_size, |x: i64| x);
-
-    let unit = if let Some(PrimitiveLogicalType::Timestamp { unit, .. }) = logical_type {
-        unit
-    } else {
-        return Ok(dyn_iter(iden(iter)));
-    };
-
-    Ok(match (unit, time_unit) {
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Second) => dyn_iter(op(iter, |x| x / 1_000)),
-        (ParquetTimeUnit::Microseconds, TimeUnit::Second) => dyn_iter(op(iter, |x| x / 1_000_000)),
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Second) => {
-            dyn_iter(op(iter, |x| x / 1_000_000_000))
-        }
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Millisecond) => dyn_iter(iden(iter)),
-        (ParquetTimeUnit::Microseconds, TimeUnit::Millisecond) => dyn_iter(op(iter, |x| x / 1_000)),
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Millisecond) => {
-            dyn_iter(op(iter, |x| x / 1_000_000))
-        }
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Microsecond) => dyn_iter(op(iter, |x| x * 1_000)),
-        (ParquetTimeUnit::Microseconds, TimeUnit::Microsecond) => dyn_iter(iden(iter)),
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Microsecond) => dyn_iter(op(iter, |x| x / 1_000)),
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Nanosecond) => {
-            dyn_iter(op(iter, |x| x * 1_000_000))
-        }
-        (ParquetTimeUnit::Microseconds, TimeUnit::Nanosecond) => dyn_iter(op(iter, |x| x * 1_000)),
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Nanosecond) => dyn_iter(iden(iter)),
-    })
+    let (factor, is_multiplier) = unifiy_timestmap_unit(logical_type, time_unit);
+    match (factor, is_multiplier) {
+        (1, _) => Ok(dyn_iter(iden(iter))),
+        (a, true) => Ok(dyn_iter(op(iter, move |x| x * a))),
+        (a, false) => Ok(dyn_iter(op(iter, move |x| x / a))),
+    }
 }
 
 fn timestamp_dict<'a, K: DictionaryKey, I: 'a + DataPages>(
@@ -347,130 +353,38 @@ fn timestamp_dict<'a, K: DictionaryKey, I: 'a + DataPages>(
     time_unit: TimeUnit,
 ) -> Result<ArrayIter<'a>> {
     if physical_type == &PhysicalType::Int96 {
-        if time_unit == TimeUnit::Nanosecond {
-            return Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
+        let (factor, is_multiplier) = unifiy_timestmap_unit(logical_type, time_unit);
+        return match (factor, is_multiplier) {
+            (a, true) => Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
                 pages,
                 DataType::Timestamp(TimeUnit::Nanosecond, None),
                 chunk_size,
-                int96_to_i64_ns,
-            )));
-        } else {
-            return Err(Error::nyi("Can't decode int96 to timestamp other than ns"));
-        }
+                move |x| int96_to_i64_ns(x) * a,
+            ))),
+            (a, false) => Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
+                pages,
+                DataType::Timestamp(TimeUnit::Nanosecond, None),
+                chunk_size,
+                move |x| int96_to_i64_ns(x) / a,
+            ))),
+        };
     };
 
-    let unit = if let Some(PrimitiveLogicalType::Timestamp { unit, .. }) = logical_type {
-        unit
-    } else {
-        return Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
+    let (factor, is_multiplier) = unifiy_timestmap_unit(logical_type, time_unit);
+    match (factor, is_multiplier) {
+        (a, true) => Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
             pages,
             data_type,
             chunk_size,
-            |x: i64| x,
-        )));
-    };
-
-    Ok(match (unit, time_unit) {
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Second) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000,
-            ))
-        }
-        (ParquetTimeUnit::Microseconds, TimeUnit::Second) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000_000,
-            ))
-        }
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Second) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000_000_000,
-            ))
-        }
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Millisecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x,
-            ))
-        }
-        (ParquetTimeUnit::Microseconds, TimeUnit::Millisecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000,
-            ))
-        }
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Millisecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000_000,
-            ))
-        }
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Microsecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x * 1_000,
-            ))
-        }
-        (ParquetTimeUnit::Microseconds, TimeUnit::Microsecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x,
-            ))
-        }
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Microsecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x / 1_000,
-            ))
-        }
-
-        (ParquetTimeUnit::Milliseconds, TimeUnit::Nanosecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x * 1_000_000,
-            ))
-        }
-        (ParquetTimeUnit::Microseconds, TimeUnit::Nanosecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x * 1_000,
-            ))
-        }
-        (ParquetTimeUnit::Nanoseconds, TimeUnit::Nanosecond) => {
-            dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
-                pages,
-                data_type,
-                chunk_size,
-                |x: i64| x,
-            ))
-        }
-    })
+            move |x: i64| x * a,
+        ))),
+        (a, false) => Ok(dyn_iter(primitive::DictIter::<K, _, _, _, _>::new(
+            pages,
+            data_type,
+            chunk_size,
+            move |x: i64| x / a,
+        ))),
+    }
 }
 
 fn dict_read<'a, K: DictionaryKey, I: 'a + DataPages>(


Test patch:
diff --git a/tests/it/compute/boolean.rs b/tests/it/compute/boolean.rs
index fb0d1c6da3..37174f224a 100644
--- a/tests/it/compute/boolean.rs
+++ b/tests/it/compute/boolean.rs
@@ -7,7 +7,7 @@ use std::iter::FromIterator;
 fn array_and() {
     let a = BooleanArray::from_slice(vec![false, false, true, true]);
     let b = BooleanArray::from_slice(vec![false, true, false, true]);
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, false, false, true]);
 
@@ -18,7 +18,7 @@ fn array_and() {
 fn array_or() {
     let a = BooleanArray::from_slice(vec![false, false, true, true]);
     let b = BooleanArray::from_slice(vec![false, true, false, true]);
-    let c = or(&a, &b).unwrap();
+    let c = or(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, true, true, true]);
 
@@ -49,7 +49,7 @@ fn array_or_validity() {
         Some(false),
         Some(true),
     ]);
-    let c = or(&a, &b).unwrap();
+    let c = or(&a, &b);
 
     let expected = BooleanArray::from(vec![
         None,
@@ -100,7 +100,7 @@ fn array_and_validity() {
         Some(false),
         Some(true),
     ]);
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from(vec![
         None,
@@ -128,7 +128,7 @@ fn array_and_sliced_same_offset() {
 
     let a = a.slice(8, 4);
     let b = b.slice(8, 4);
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, false, false, true]);
 
@@ -147,7 +147,7 @@ fn array_and_sliced_same_offset_mod8() {
     let a = a.slice(0, 4);
     let b = b.slice(8, 4);
 
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, false, false, true]);
 
@@ -163,7 +163,7 @@ fn array_and_sliced_offset1() {
 
     let a = a.slice(8, 4);
 
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, false, false, true]);
 
@@ -179,7 +179,7 @@ fn array_and_sliced_offset2() {
 
     let b = b.slice(8, 4);
 
-    let c = and(&a, &b).unwrap();
+    let c = and(&a, &b);
 
     let expected = BooleanArray::from_slice(vec![false, false, false, true]);
 
@@ -204,7 +204,7 @@ fn array_and_validity_offset() {
     let b = b.slice(2, 4);
     let b = b.as_any().downcast_ref::<BooleanArray>().unwrap();
 
-    let c = and(a, b).unwrap();
+    let c = and(a, b);
 
     let expected = BooleanArray::from(vec![Some(false), Some(false), None, Some(true)]);
 
diff --git a/tests/it/compute/boolean_kleene.rs b/tests/it/compute/boolean_kleene.rs
index 3bf0b8ef37..c1c034ca9f 100644
--- a/tests/it/compute/boolean_kleene.rs
+++ b/tests/it/compute/boolean_kleene.rs
@@ -26,7 +26,7 @@ fn and_generic() {
         Some(false),
         Some(true),
     ]);
-    let c = and(&lhs, &rhs).unwrap();
+    let c = and(&lhs, &rhs);
 
     let expected = BooleanArray::from(&[
         None,
@@ -67,7 +67,7 @@ fn or_generic() {
         Some(false),
         Some(true),
     ]);
-    let c = or(&a, &b).unwrap();
+    let c = or(&a, &b);
 
     let expected = BooleanArray::from(&[
         None,
@@ -90,7 +90,7 @@ fn or_right_nulls() {
 
     let b = BooleanArray::from(&[Some(true), Some(false), None, Some(true), Some(false), None]);
 
-    let c = or(&a, &b).unwrap();
+    let c = or(&a, &b);
 
     let expected = BooleanArray::from(&[
         Some(true),
@@ -117,7 +117,7 @@ fn or_left_nulls() {
 
     let b = BooleanArray::from_slice(&[false, false, false, true, true, true]);
 
-    let c = or(&a, &b).unwrap();
+    let c = or(&a, &b);
 
     let expected = BooleanArray::from(vec![
         Some(true),