Skip to content

Commit 783ede2

Browse files
authored
Merge branch 'main' into fsl-len
2 parents 6e65d40 + d48bf0d commit 783ede2

File tree

5 files changed

+292
-66
lines changed

5 files changed

+292
-66
lines changed

arrow-array/src/array/primitive_array.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,9 @@ pub use crate::types::ArrowPrimitiveType;
493493
///
494494
/// # Example: From a Vec
495495
///
496+
/// *Note*: Converting a `Vec` to a `PrimitiveArray` does not copy the data.
497+
/// The new `PrimitiveArray` uses the same underlying allocation from the `Vec`.
498+
///
496499
/// ```
497500
/// # use arrow_array::{Array, PrimitiveArray, types::Int32Type};
498501
/// let arr: PrimitiveArray<Int32Type> = vec![1, 2, 3, 4].into();
@@ -501,6 +504,33 @@ pub use crate::types::ArrowPrimitiveType;
501504
/// assert_eq!(arr.values(), &[1, 2, 3, 4])
502505
/// ```
503506
///
507+
/// # Example: To a `Vec<T>`
508+
///
509+
/// *Note*: In some cases, converting `PrimitiveArray` to a `Vec` is zero-copy
510+
/// and does not copy the data (see [`Buffer::into_vec`] for conditions). In
511+
/// such cases, the `Vec` will use the same underlying memory allocation from
512+
/// the `PrimitiveArray`.
513+
///
514+
/// The Rust compiler generates highly optimized code for operations on
515+
/// Vec, so using a Vec can often be faster than using a PrimitiveArray directly.
516+
///
517+
/// ```
518+
/// # use arrow_array::{Array, PrimitiveArray, types::Int32Type};
519+
/// let arr = PrimitiveArray::<Int32Type>::from(vec![1, 2, 3, 4]);
520+
/// let starting_ptr = arr.values().as_ptr();
521+
/// // split into its parts
522+
/// let (datatype, buffer, nulls) = arr.into_parts();
523+
/// // Convert the buffer to a Vec<i32> (zero copy)
524+
/// // (note this requires that there are no other references)
525+
/// let mut vec: Vec<i32> = buffer.into();
526+
/// vec[2] = 300;
527+
/// // put the parts back together
528+
/// let arr = PrimitiveArray::<Int32Type>::try_new(vec.into(), nulls).unwrap();
529+
/// assert_eq!(arr.values(), &[1, 2, 300, 4]);
530+
/// // The same allocation was used
531+
/// assert_eq!(starting_ptr, arr.values().as_ptr());
532+
/// ```
533+
///
504534
/// # Example: From an optional Vec
505535
///
506536
/// ```

arrow-buffer/src/buffer/immutable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ impl Buffer {
388388
/// # Errors
389389
///
390390
/// Returns `Err(self)` if
391-
/// 1. this buffer does not have the same [`Layout`] as the destination Vec
392-
/// 2. contains a non-zero offset
391+
/// 1. The buffer does not have the same [`Layout`] as the destination Vec
392+
/// 2. The buffer contains a non-zero offset
393393
/// 3. The buffer is shared
394394
pub fn into_vec<T: ArrowNativeType>(self) -> Result<Vec<T>, Self> {
395395
let layout = match self.data.deallocation() {

arrow-buffer/src/buffer/scalar.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,38 @@ use std::ops::Deref;
2929
/// with the following differences:
3030
///
3131
/// - slicing and cloning is O(1).
32-
/// - it supports external allocated memory
32+
/// - support for external allocated memory (e.g. via FFI).
3333
///
34+
/// See [`Buffer`] for more low-level memory management details.
35+
///
36+
/// # Example: Convert to/from Vec (without copies)
37+
///
38+
/// (See [`Buffer::from_vec`] and [`Buffer::into_vec`] for a lower level API)
3439
/// ```
3540
/// # use arrow_buffer::ScalarBuffer;
3641
/// // Zero-copy conversion from Vec
3742
/// let buffer = ScalarBuffer::from(vec![1, 2, 3]);
3843
/// assert_eq!(&buffer, &[1, 2, 3]);
44+
/// // convert the buffer back to Vec without copy assuming:
45+
/// // 1. the inner buffer is not sliced
46+
/// // 2. the inner buffer uses standard allocation
47+
/// // 3. there are no other references to the inner buffer
48+
/// let vec: Vec<i32> = buffer.into();
49+
/// assert_eq!(&vec, &[1, 2, 3]);
50+
/// ```
3951
///
52+
/// # Example: Zero copy slicing
53+
/// ```
54+
/// # use arrow_buffer::ScalarBuffer;
55+
/// let buffer = ScalarBuffer::from(vec![1, 2, 3]);
56+
/// assert_eq!(&buffer, &[1, 2, 3]);
4057
/// // Zero-copy slicing
4158
/// let sliced = buffer.slice(1, 2);
4259
/// assert_eq!(&sliced, &[2, 3]);
60+
/// // Original buffer is unchanged
61+
/// assert_eq!(&buffer, &[1, 2, 3]);
62+
/// // converting the sliced buffer back to Vec incurs a copy
63+
/// let vec: Vec<i32> = sliced.into();
4364
/// ```
4465
#[derive(Clone, Default)]
4566
pub struct ScalarBuffer<T: ArrowNativeType> {

arrow-schema/src/datatype_display.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,9 @@ impl fmt::Display for DataType {
135135
Ok(())
136136
}
137137
Self::Union(union_fields, union_mode) => {
138-
write!(f, "Union({union_mode:?}, ")?;
138+
write!(f, "Union({union_mode:?}")?;
139139
if !union_fields.is_empty() {
140+
write!(f, ", ")?;
140141
let fields_str = union_fields
141142
.iter()
142143
.map(|v| {

0 commit comments

Comments
 (0)