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 32b385b946 [Variant] VariantArrayBuilder uses MetadataBuilder and 
ValueBuilder (#8206)
32b385b946 is described below

commit 32b385b9465c6512c66f95f397acfa126368840c
Author: Ryan Johnson <scov...@users.noreply.github.com>
AuthorDate: Sat Aug 23 04:07:57 2025 -0700

    [Variant] VariantArrayBuilder uses MetadataBuilder and ValueBuilder (#8206)
    
    # Which issue does this PR close?
    
    - Closes https://github.com/apache/arrow-rs/issues/8205
    
    # Rationale for this change
    
    `VariantArrayBuilder` had a very complex choreography with the
    `VariantBuilder` API, that required lots of manual drop glue to deal
    with ownership transfers between it and the `VariantArrayVariantBuilder`
    it delegates the actual work to. Rework the whole thing to use a
    (now-reusable) `MetadataBuilder` and `ValueBuilder`, with rollbacks
    largely handled by `ParentState` -- just like the other builders in the
    parquet-variant crate.
    
    # What changes are included in this PR?
    
    Five changes (curated as five commits that reviewers may want to examine
    individually):
    1. Make a bunch of parquet-variant builder infrastructure public, so
    that `VariantArrayBuilder` can access it from the
    parquet-variant-compute crate.
    2. Make `MetadataBuilder` reusable. Its `finish` method appends the
    bytes of a new serialized metadata dictionary to the underlying buffer
    and resets the remaining builder state. The builder is thus ready to
    create a brand new metadata dictionary whose serialized bytes will also
    be appended to the underlying buffer once finished.
    3. Rework `VariantArrayBuilder` to use `MetadataBuilder` and
    `ValueBuilder`, coordinated via `ParentState`. This is the main feature
    of the PR and also the most complicated/subtle.
    4. Delete now-unused code that had been added previously in order to
    support the old implementation of `VariantArrayBuilder`.
    5. Add missing doc comments for now-public types and methods
    
    
    # Are these changes tested?
    
    Existing variant array builder tests cover the change.
    
    # Are there any user-facing changes?
    
    A lot of builder-related types and methods from the parquet-variant
    crate are now public.
---
 .../src/variant_array_builder.rs                   | 165 +++++---------
 parquet-variant/src/builder.rs                     | 243 +++++----------------
 2 files changed, 111 insertions(+), 297 deletions(-)

diff --git a/parquet-variant-compute/src/variant_array_builder.rs 
b/parquet-variant-compute/src/variant_array_builder.rs
index 969dc3776a..69f631e34d 100644
--- a/parquet-variant-compute/src/variant_array_builder.rs
+++ b/parquet-variant-compute/src/variant_array_builder.rs
@@ -20,7 +20,8 @@
 use crate::VariantArray;
 use arrow::array::{ArrayRef, BinaryViewArray, BinaryViewBuilder, 
NullBufferBuilder, StructArray};
 use arrow_schema::{ArrowError, DataType, Field, Fields};
-use parquet_variant::{ListBuilder, ObjectBuilder, Variant, VariantBuilder, 
VariantBuilderExt};
+use parquet_variant::{ListBuilder, ObjectBuilder, Variant, VariantBuilderExt};
+use parquet_variant::{MetadataBuilder, ParentState, ValueBuilder};
 use std::sync::Arc;
 
 /// A builder for [`VariantArray`]
@@ -72,12 +73,12 @@ use std::sync::Arc;
 pub struct VariantArrayBuilder {
     /// Nulls
     nulls: NullBufferBuilder,
-    /// buffer for all the metadata
-    metadata_buffer: Vec<u8>,
+    /// builder for all the metadata
+    metadata_builder: MetadataBuilder,
     /// ending offset for each serialized metadata dictionary in the buffer
     metadata_offsets: Vec<usize>,
-    /// buffer for values
-    value_buffer: Vec<u8>,
+    /// builder for values
+    value_builder: ValueBuilder,
     /// ending offset for each serialized variant value in the buffer
     value_offsets: Vec<usize>,
     /// The fields of the final `StructArray`
@@ -95,9 +96,9 @@ impl VariantArrayBuilder {
 
         Self {
             nulls: NullBufferBuilder::new(row_capacity),
-            metadata_buffer: Vec::new(), // todo allocation capacity
+            metadata_builder: MetadataBuilder::default(),
             metadata_offsets: Vec::with_capacity(row_capacity),
-            value_buffer: Vec::new(),
+            value_builder: ValueBuilder::new(),
             value_offsets: Vec::with_capacity(row_capacity),
             fields: Fields::from(vec![metadata_field, value_field]),
         }
@@ -107,15 +108,17 @@ impl VariantArrayBuilder {
     pub fn build(self) -> VariantArray {
         let Self {
             mut nulls,
-            metadata_buffer,
+            metadata_builder,
             metadata_offsets,
-            value_buffer,
+            value_builder,
             value_offsets,
             fields,
         } = self;
 
+        let metadata_buffer = metadata_builder.into_inner();
         let metadata_array = binary_view_array_from_buffers(metadata_buffer, 
metadata_offsets);
 
+        let value_buffer = value_builder.into_inner();
         let value_array = binary_view_array_from_buffers(value_buffer, 
value_offsets);
 
         // The build the final struct array
@@ -136,14 +139,14 @@ impl VariantArrayBuilder {
     pub fn append_null(&mut self) {
         self.nulls.append_null();
         // The subfields are expected to be non-nullable according to the 
parquet variant spec.
-        self.metadata_offsets.push(self.metadata_buffer.len());
-        self.value_offsets.push(self.value_buffer.len());
+        self.metadata_offsets.push(self.metadata_builder.offset());
+        self.value_offsets.push(self.value_builder.offset());
     }
 
     /// Append the [`Variant`] to the builder as the next row
     pub fn append_variant(&mut self, variant: Variant) {
         let mut direct_builder = self.variant_builder();
-        direct_builder.variant_builder.append_value(variant);
+        direct_builder.append_value(variant);
         direct_builder.finish()
     }
 
@@ -194,32 +197,23 @@ impl VariantArrayBuilder {
 ///
 /// See [`VariantArrayBuilder::variant_builder`] for an example
 pub struct VariantArrayVariantBuilder<'a> {
-    /// was finish called?
-    finished: bool,
-    /// starting offset in the variant_builder's `metadata` buffer
-    metadata_offset: usize,
-    /// starting offset in the variant_builder's `value` buffer
-    value_offset: usize,
-    /// Parent array builder that this variant builder writes to. Buffers
-    /// have been moved into the variant builder, and must be returned on
-    /// drop
-    array_builder: &'a mut VariantArrayBuilder,
-    /// Builder for the in progress variant value, temporarily owns the buffers
-    /// from `array_builder`
-    variant_builder: VariantBuilder,
+    parent_state: ParentState<'a>,
+    metadata_offsets: &'a mut Vec<usize>,
+    value_offsets: &'a mut Vec<usize>,
+    nulls: &'a mut NullBufferBuilder,
 }
 
 impl VariantBuilderExt for VariantArrayVariantBuilder<'_> {
     fn append_value<'m, 'v>(&mut self, value: impl Into<Variant<'m, 'v>>) {
-        self.variant_builder.append_value(value);
+        ValueBuilder::append_variant(self.parent_state(), value.into());
     }
 
     fn try_new_list(&mut self) -> Result<ListBuilder<'_>, ArrowError> {
-        Ok(self.variant_builder.new_list())
+        Ok(ListBuilder::new(self.parent_state(), false))
     }
 
     fn try_new_object(&mut self) -> Result<ObjectBuilder<'_>, ArrowError> {
-        Ok(self.variant_builder.new_object())
+        Ok(ObjectBuilder::new(self.parent_state(), false))
     }
 }
 
@@ -228,103 +222,40 @@ impl<'a> VariantArrayVariantBuilder<'a> {
     ///
     /// Note this is not public as this is a structure that is logically
     /// part of the [`VariantArrayBuilder`] and relies on its internal 
structure
-    fn new(array_builder: &'a mut VariantArrayBuilder) -> Self {
-        // append directly into the metadata and value buffers
-        let metadata_buffer = std::mem::take(&mut 
array_builder.metadata_buffer);
-        let value_buffer = std::mem::take(&mut array_builder.value_buffer);
-        let metadata_offset = metadata_buffer.len();
-        let value_offset = value_buffer.len();
+    fn new(builder: &'a mut VariantArrayBuilder) -> Self {
+        let parent_state =
+            ParentState::variant(&mut builder.value_builder, &mut 
builder.metadata_builder);
         VariantArrayVariantBuilder {
-            finished: false,
-            metadata_offset,
-            value_offset,
-            variant_builder: VariantBuilder::new_with_buffers(metadata_buffer, 
value_buffer),
-            array_builder,
+            parent_state,
+            metadata_offsets: &mut builder.metadata_offsets,
+            value_offsets: &mut builder.value_offsets,
+            nulls: &mut builder.nulls,
         }
     }
 
-    /// Return a reference to the underlying `VariantBuilder`
-    pub fn inner(&self) -> &VariantBuilder {
-        &self.variant_builder
-    }
-
-    /// Return a mutable reference to the underlying `VariantBuilder`
-    pub fn inner_mut(&mut self) -> &mut VariantBuilder {
-        &mut self.variant_builder
-    }
-
     /// Called to finish the in progress variant and write it to the underlying
     /// buffers
     ///
     /// Note if you do not call finish, on drop any changes made to the
     /// underlying buffers will be rolled back.
     pub fn finish(mut self) {
-        self.finished = true;
-
-        let metadata_offset = self.metadata_offset;
-        let value_offset = self.value_offset;
-        // get the buffers back from the variant builder
-        let (metadata_buffer, value_buffer) = std::mem::take(&mut 
self.variant_builder).finish();
-
-        // Sanity Check: if the buffers got smaller, something went wrong 
(previous data was lost)
-        assert!(
-            metadata_offset <= metadata_buffer.len(),
-            "metadata length decreased unexpectedly"
-        );
-        assert!(
-            value_offset <= value_buffer.len(),
-            "value length decreased unexpectedly"
-        );
-
-        // commit the changes by putting the
-        // ending offsets into the parent array builder.
-        let builder = &mut self.array_builder;
-        builder.metadata_offsets.push(metadata_buffer.len());
-        builder.value_offsets.push(value_buffer.len());
-        builder.nulls.append_non_null();
+        // Record the ending offsets after finishing metadata and finish the 
parent state.
+        let (value_builder, metadata_builder) = 
self.parent_state.value_and_metadata_builders();
+        self.metadata_offsets.push(metadata_builder.finish());
+        self.value_offsets.push(value_builder.offset());
+        self.nulls.append_non_null();
+        self.parent_state.finish();
+    }
 
-        // put the buffers back into the array builder
-        builder.metadata_buffer = metadata_buffer;
-        builder.value_buffer = value_buffer;
+    fn parent_state(&mut self) -> ParentState<'_> {
+        let (value_builder, metadata_builder) = 
self.parent_state.value_and_metadata_builders();
+        ParentState::variant(value_builder, metadata_builder)
     }
 }
 
+// Empty Drop to help with borrow checking - warns users if they forget to 
call finish()
 impl Drop for VariantArrayVariantBuilder<'_> {
-    /// If the builder was not finished, roll back any changes made to the
-    /// underlying buffers (by truncating them)
-    fn drop(&mut self) {
-        if self.finished {
-            return;
-        }
-
-        // if the object was not finished, need to rollback any changes by
-        // truncating the buffers to the original offsets
-        let metadata_offset = self.metadata_offset;
-        let value_offset = self.value_offset;
-
-        // get the buffers back from the variant builder
-        let (mut metadata_buffer, mut value_buffer) =
-            std::mem::take(&mut self.variant_builder).into_buffers();
-
-        // Sanity Check: if the buffers got smaller, something went wrong 
(previous data was lost) so panic immediately
-        metadata_buffer
-            .len()
-            .checked_sub(metadata_offset)
-            .expect("metadata length decreased unexpectedly");
-        value_buffer
-            .len()
-            .checked_sub(value_offset)
-            .expect("value length decreased unexpectedly");
-
-        // Note this truncate is fast because truncate doesn't free any memory:
-        // it just has to drop elements (and u8 doesn't have a destructor)
-        metadata_buffer.truncate(metadata_offset);
-        value_buffer.truncate(value_offset);
-
-        // put the buffers back into the array builder
-        self.array_builder.metadata_buffer = metadata_buffer;
-        self.array_builder.value_buffer = value_buffer;
-    }
+    fn drop(&mut self) {}
 }
 
 fn binary_view_array_from_buffers(buffer: Vec<u8>, offsets: Vec<usize>) -> 
BinaryViewArray {
@@ -457,12 +388,18 @@ mod test {
         assert_eq!(variant_array.len(), 2);
         assert!(!variant_array.is_null(0));
         let variant = variant_array.value(0);
-        let variant = variant.as_object().expect("variant to be an object");
-        assert_eq!(variant.get("foo").unwrap(), Variant::from(1i32));
+        assert_eq!(
+            variant.get_object_field("foo"),
+            Some(Variant::from(1i32)),
+            "Expected an object with field \"foo\", got: {variant:?}"
+        );
 
         assert!(!variant_array.is_null(1));
         let variant = variant_array.value(1);
-        let variant = variant.as_object().expect("variant to be an object");
-        assert_eq!(variant.get("baz").unwrap(), Variant::from(3i32));
+        assert_eq!(
+            variant.get_object_field("baz"),
+            Some(Variant::from(3i32)),
+            "Expected an object with field \"baz\", got: {variant:?}"
+        );
     }
 }
diff --git a/parquet-variant/src/builder.rs b/parquet-variant/src/builder.rs
index aa202460a4..2d51b6d2fd 100644
--- a/parquet-variant/src/builder.rs
+++ b/parquet-variant/src/builder.rs
@@ -86,27 +86,15 @@ fn append_packed_u32(dest: &mut Vec<u8>, value: u32, 
value_size: usize) {
 ///
 /// You can reuse an existing `Vec<u8>` by using the `from` impl
 #[derive(Debug, Default)]
-struct ValueBuilder(Vec<u8>);
+pub struct ValueBuilder(Vec<u8>);
 
 impl ValueBuilder {
     /// Construct a ValueBuffer that will write to a new underlying `Vec`
-    fn new() -> Self {
+    pub fn new() -> Self {
         Default::default()
     }
 }
 
-impl From<Vec<u8>> for ValueBuilder {
-    fn from(value: Vec<u8>) -> Self {
-        Self(value)
-    }
-}
-
-impl From<ValueBuilder> for Vec<u8> {
-    fn from(value_buffer: ValueBuilder) -> Self {
-        value_buffer.0
-    }
-}
-
 impl ValueBuilder {
     fn append_u8(&mut self, term: u8) {
         self.0.push(term);
@@ -120,8 +108,9 @@ impl ValueBuilder {
         self.0.push(primitive_header(primitive_type));
     }
 
-    fn into_inner(self) -> Vec<u8> {
-        self.into()
+    /// Returns the underlying buffer, consuming self
+    pub fn into_inner(self) -> Vec<u8> {
+        self.0
     }
 
     fn inner_mut(&mut self) -> &mut Vec<u8> {
@@ -292,7 +281,8 @@ impl ValueBuilder {
         Ok(())
     }
 
-    fn offset(&self) -> usize {
+    /// Returns the current size of the underlying buffer
+    pub fn offset(&self) -> usize {
         self.0.len()
     }
 
@@ -302,7 +292,7 @@ impl ValueBuilder {
     ///
     /// This method will panic if the variant contains duplicate field names 
in objects
     /// when validation is enabled. For a fallible version, use 
[`ValueBuilder::try_append_variant`]
-    fn append_variant(mut state: ParentState<'_>, variant: Variant<'_, '_>) {
+    pub fn append_variant(mut state: ParentState<'_>, variant: Variant<'_, 
'_>) {
         let builder = state.value_builder();
         match variant {
             Variant::Null => builder.append_null(),
@@ -437,7 +427,7 @@ impl ValueBuilder {
 ///
 /// You can use an existing `Vec<u8>` as the metadata buffer by using the 
`from` impl.
 #[derive(Default, Debug)]
-struct MetadataBuilder {
+pub struct MetadataBuilder {
     // Field names -- field_ids are assigned in insert order
     field_names: IndexSet<String>,
 
@@ -448,16 +438,6 @@ struct MetadataBuilder {
     metadata_buffer: Vec<u8>,
 }
 
-/// Create a new MetadataBuilder that will write to the specified metadata 
buffer
-impl From<Vec<u8>> for MetadataBuilder {
-    fn from(metadata_buffer: Vec<u8>) -> Self {
-        Self {
-            metadata_buffer,
-            ..Default::default()
-        }
-    }
-}
-
 impl MetadataBuilder {
     /// Upsert field name to dictionary, return its ID
     fn upsert_field_name(&mut self, field_name: &str) -> u32 {
@@ -477,6 +457,11 @@ impl MetadataBuilder {
         id as u32
     }
 
+    /// The current length of the underlying metadata buffer
+    pub fn offset(&self) -> usize {
+        self.metadata_buffer.len()
+    }
+
     /// Returns the number of field names stored in the metadata builder.
     /// Note: this method should be the only place to call 
`self.field_names.len()`
     ///
@@ -498,17 +483,18 @@ impl MetadataBuilder {
         self.field_names.iter().map(|k| k.len()).sum()
     }
 
-    fn finish(self) -> Vec<u8> {
+    /// Finalizes the metadata dictionary and appends its serialized bytes to 
the underlying buffer,
+    /// returning the resulting [`Self::offset`]. The builder state is reset 
and ready to start
+    /// building a new metadata dictionary.
+    pub fn finish(&mut self) -> usize {
         let nkeys = self.num_field_names();
 
         // Calculate metadata size
         let total_dict_size: usize = self.metadata_size();
 
-        let Self {
-            field_names,
-            is_sorted,
-            mut metadata_buffer,
-        } = self;
+        let metadata_buffer = &mut self.metadata_buffer;
+        let is_sorted = std::mem::take(&mut self.is_sorted);
+        let field_names = std::mem::take(&mut self.field_names);
 
         // Determine appropriate offset size based on the larger of dict size 
or total string size
         let max_offset = std::cmp::max(total_dict_size, nkeys);
@@ -524,27 +510,27 @@ impl MetadataBuilder {
         metadata_buffer.push(0x01 | (is_sorted as u8) << 4 | ((offset_size - 
1) << 6));
 
         // Write dictionary size
-        write_offset(&mut metadata_buffer, nkeys, offset_size);
+        write_offset(metadata_buffer, nkeys, offset_size);
 
         // Write offsets
         let mut cur_offset = 0;
         for key in field_names.iter() {
-            write_offset(&mut metadata_buffer, cur_offset, offset_size);
+            write_offset(metadata_buffer, cur_offset, offset_size);
             cur_offset += key.len();
         }
         // Write final offset
-        write_offset(&mut metadata_buffer, cur_offset, offset_size);
+        write_offset(metadata_buffer, cur_offset, offset_size);
 
         // Write string data
         for key in field_names {
             metadata_buffer.extend_from_slice(key.as_bytes());
         }
 
-        metadata_buffer
+        metadata_buffer.len()
     }
 
-    /// Return the inner buffer, without finalizing any in progress metadata.
-    pub(crate) fn into_inner(self) -> Vec<u8> {
+    /// Returns the inner buffer, consuming self without finalizing any in 
progress metadata.
+    pub fn into_inner(self) -> Vec<u8> {
         self.metadata_buffer
     }
 }
@@ -585,7 +571,7 @@ impl<S: AsRef<str>> Extend<S> for MetadataBuilder {
 /// treat the variants as a union, so that accessing a `value_builder` or 
`metadata_builder` is
 /// branch-free.
 #[derive(Debug)]
-enum ParentState<'a> {
+pub enum ParentState<'a> {
     Variant {
         value_builder: &'a mut ValueBuilder,
         saved_value_builder_offset: usize,
@@ -614,7 +600,10 @@ enum ParentState<'a> {
 }
 
 impl<'a> ParentState<'a> {
-    fn variant(
+    /// Creates a new instance suitable for a top-level variant builder
+    /// (e.g. [`VariantBuilder`]). The value and metadata builder state is 
checkpointed and will
+    /// roll back on drop, unless [`Self::finish`] is called.
+    pub fn variant(
         value_builder: &'a mut ValueBuilder,
         metadata_builder: &'a mut MetadataBuilder,
     ) -> Self {
@@ -627,7 +616,10 @@ impl<'a> ParentState<'a> {
         }
     }
 
-    fn list(
+    /// Creates a new instance suitable for a [`ListBuilder`]. The value and 
metadata builder state
+    /// is checkpointed and will roll back on drop, unless [`Self::finish`] is 
called. The new
+    /// element's offset is also captured eagerly and will also roll back if 
not finished.
+    pub fn list(
         value_builder: &'a mut ValueBuilder,
         metadata_builder: &'a mut MetadataBuilder,
         offsets: &'a mut Vec<usize>,
@@ -651,7 +643,12 @@ impl<'a> ParentState<'a> {
         }
     }
 
-    fn try_object(
+    /// Creates a new instance suitable for an [`ObjectBuilder`]. The value 
and metadata builder state
+    /// is checkpointed and will roll back on drop, unless [`Self::finish`] is 
called. The new
+    /// field's name and offset are also captured eagerly and will also roll 
back if not finished.
+    ///
+    /// The call fails if the field name is invalid (e.g. because it 
duplicates an existing field).
+    pub fn try_object(
         value_builder: &'a mut ValueBuilder,
         metadata_builder: &'a mut MetadataBuilder,
         fields: &'a mut IndexMap<u32, usize>,
@@ -717,8 +714,8 @@ impl<'a> ParentState<'a> {
         }
     }
 
-    // Mark the insertion as having succeeded.
-    fn finish(&mut self) {
+    /// Mark the insertion as having succeeded. Internal state will no longer 
roll back on drop.
+    pub fn finish(&mut self) {
         *self.is_finished() = true
     }
 
@@ -778,7 +775,7 @@ impl<'a> ParentState<'a> {
 
     /// Return mutable references to the value and metadata builders that this
     /// parent state is using.
-    fn value_and_metadata_builders(&mut self) -> (&mut ValueBuilder, &mut 
MetadataBuilder) {
+    pub fn value_and_metadata_builders(&mut self) -> (&mut ValueBuilder, &mut 
MetadataBuilder) {
         match self {
             ParentState::Variant {
                 value_builder,
@@ -986,41 +983,6 @@ impl Drop for ParentState<'_> {
 /// );
 ///
 /// ```
-/// # Example: Reusing Buffers
-///
-/// You can use the [`VariantBuilder`] to write into existing buffers (for
-/// example to write multiple variants back to back in the same buffer)
-///
-/// ```
-/// // we will write two variants back to back
-/// use parquet_variant::{Variant, VariantBuilder};
-/// // Append 12345
-/// let mut builder = VariantBuilder::new();
-/// builder.append_value(12345);
-/// let (metadata, value) = builder.finish();
-/// // remember where the first variant ends
-/// let (first_meta_offset, first_meta_len) = (0, metadata.len());
-/// let (first_value_offset, first_value_len) = (0, value.len());
-///
-/// // now, append a second variant to the same buffers
-/// let mut builder = VariantBuilder::new_with_buffers(metadata, value);
-/// builder.append_value("Foo");
-/// let (metadata, value) = builder.finish();
-///
-/// // The variants can be referenced in their appropriate location
-/// let variant1 = Variant::new(
-///   &metadata[first_meta_offset..first_meta_len],
-///   &value[first_value_offset..first_value_len]
-///  );
-/// assert_eq!(variant1, Variant::Int32(12345));
-///
-/// let variant2 = Variant::new(
-///   &metadata[first_meta_len..],
-///   &value[first_value_len..]
-///  );
-/// assert_eq!(variant2, Variant::from("Foo"));
-/// ```
-///
 /// # Example: Unique Field Validation
 ///
 /// This example shows how enabling unique field validation will cause an error
@@ -1100,16 +1062,6 @@ impl VariantBuilder {
         self
     }
 
-    /// Create a new VariantBuilder that will write the metadata and values to
-    /// the specified buffers.
-    pub fn new_with_buffers(metadata_buffer: Vec<u8>, value_buffer: Vec<u8>) 
-> Self {
-        Self {
-            value_builder: ValueBuilder::from(value_buffer),
-            metadata_builder: MetadataBuilder::from(metadata_buffer),
-            validate_unique_fields: false,
-        }
-    }
-
     /// Enables validation of unique field keys in nested objects.
     ///
     /// This setting is propagated to all [`ObjectBuilder`]s created through 
this [`VariantBuilder`]
@@ -1215,19 +1167,8 @@ impl VariantBuilder {
     }
 
     /// Finish the builder and return the metadata and value buffers.
-    pub fn finish(self) -> (Vec<u8>, Vec<u8>) {
-        (
-            self.metadata_builder.finish(),
-            self.value_builder.into_inner(),
-        )
-    }
-
-    /// Return the inner metadata buffers and value buffer.
-    ///
-    /// This can be used to get the underlying buffers provided via
-    /// [`VariantBuilder::new_with_buffers`] without finalizing the metadata or
-    /// values (for rolling back changes).
-    pub fn into_buffers(self) -> (Vec<u8>, Vec<u8>) {
+    pub fn finish(mut self) -> (Vec<u8>, Vec<u8>) {
+        self.metadata_builder.finish();
         (
             self.metadata_builder.into_inner(),
             self.value_builder.into_inner(),
@@ -1246,7 +1187,8 @@ pub struct ListBuilder<'a> {
 }
 
 impl<'a> ListBuilder<'a> {
-    fn new(parent_state: ParentState<'a>, validate_unique_fields: bool) -> 
Self {
+    /// Creates a new list builder, nested on top of the given parent state.
+    pub fn new(parent_state: ParentState<'a>, validate_unique_fields: bool) -> 
Self {
         Self {
             parent_state,
             offsets: vec![],
@@ -1388,7 +1330,8 @@ pub struct ObjectBuilder<'a> {
 }
 
 impl<'a> ObjectBuilder<'a> {
-    fn new(parent_state: ParentState<'a>, validate_unique_fields: bool) -> 
Self {
+    /// Creates a new object builder, nested on top of the given parent state.
+    pub fn new(parent_state: ParentState<'a>, validate_unique_fields: bool) -> 
Self {
         Self {
             parent_state,
             fields: IndexMap::new(),
@@ -1589,18 +1532,27 @@ impl<'a> ObjectBuilder<'a> {
 /// Allows users to append values to a [`VariantBuilder`], [`ListBuilder`] or
 /// [`ObjectBuilder`]. using the same interface.
 pub trait VariantBuilderExt {
+    /// Appends a new variant value to this builder. See e.g. 
[`VariantBuilder::append_value`].
     fn append_value<'m, 'v>(&mut self, value: impl Into<Variant<'m, 'v>>);
 
+    /// Creates a nested list builder. See e.g. [`VariantBuilder::new_list`]. 
Panics if the nested
+    /// builder cannot be created, see e.g. [`ObjectBuilder::new_list`].
     fn new_list(&mut self) -> ListBuilder<'_> {
         self.try_new_list().unwrap()
     }
 
+    /// Creates a nested object builder. See e.g. 
[`VariantBuilder::new_object`]. Panics if the
+    /// nested builder cannot be created, see e.g. 
[`ObjectBuilder::new_object`].
     fn new_object(&mut self) -> ObjectBuilder<'_> {
         self.try_new_object().unwrap()
     }
 
+    /// Creates a nested list builder. See e.g. [`VariantBuilder::new_list`]. 
Returns an error if
+    /// the nested builder cannot be created, see e.g. 
[`ObjectBuilder::try_new_list`].
     fn try_new_list(&mut self) -> Result<ListBuilder<'_>, ArrowError>;
 
+    /// Creates a nested object builder. See e.g. 
[`VariantBuilder::new_object`]. Returns an error
+    /// if the nested builder cannot be created, see e.g. 
[`ObjectBuilder::try_new_object`].
     fn try_new_object(&mut self) -> Result<ObjectBuilder<'_>, ArrowError>;
 }
 
@@ -2779,81 +2731,6 @@ mod tests {
         assert_eq!(metadata.num_field_names(), 3);
     }
 
-    /// Test reusing buffers with nested objects
-    #[test]
-    fn test_with_existing_buffers_nested() {
-        let mut builder = VariantBuilder::new();
-        append_test_list(&mut builder);
-        let (m1, v1) = builder.finish();
-        let variant1 = Variant::new(&m1, &v1);
-
-        let mut builder = VariantBuilder::new();
-        append_test_object(&mut builder);
-        let (m2, v2) = builder.finish();
-        let variant2 = Variant::new(&m2, &v2);
-
-        let mut builder = VariantBuilder::new();
-        builder.append_value("This is a string");
-        let (m3, v3) = builder.finish();
-        let variant3 = Variant::new(&m3, &v3);
-
-        // Now, append those three variants to the a new buffer that is reused
-        let mut builder = VariantBuilder::new();
-        append_test_list(&mut builder);
-        let (metadata, value) = builder.finish();
-        let (meta1_offset, meta1_end) = (0, metadata.len());
-        let (value1_offset, value1_end) = (0, value.len());
-
-        // reuse same buffer
-        let mut builder = VariantBuilder::new_with_buffers(metadata, value);
-        append_test_object(&mut builder);
-        let (metadata, value) = builder.finish();
-        let (meta2_offset, meta2_end) = (meta1_end, metadata.len());
-        let (value2_offset, value2_end) = (value1_end, value.len());
-
-        // Append a string
-        let mut builder = VariantBuilder::new_with_buffers(metadata, value);
-        builder.append_value("This is a string");
-        let (metadata, value) = builder.finish();
-        let (meta3_offset, meta3_end) = (meta2_end, metadata.len());
-        let (value3_offset, value3_end) = (value2_end, value.len());
-
-        // verify we can read the variants back correctly
-        let roundtrip1 = Variant::new(
-            &metadata[meta1_offset..meta1_end],
-            &value[value1_offset..value1_end],
-        );
-        assert_eq!(roundtrip1, variant1,);
-
-        let roundtrip2 = Variant::new(
-            &metadata[meta2_offset..meta2_end],
-            &value[value2_offset..value2_end],
-        );
-        assert_eq!(roundtrip2, variant2,);
-
-        let roundtrip3 = Variant::new(
-            &metadata[meta3_offset..meta3_end],
-            &value[value3_offset..value3_end],
-        );
-        assert_eq!(roundtrip3, variant3);
-    }
-
-    /// append a simple List variant
-    fn append_test_list(builder: &mut VariantBuilder) {
-        builder
-            .new_list()
-            .with_value(1234)
-            .with_value("a string value")
-            .finish();
-    }
-
-    /// append an object variant
-    fn append_test_object(builder: &mut VariantBuilder) {
-        let mut obj = builder.new_object();
-        obj.insert("a", true);
-        obj.finish().unwrap();
-    }
-
     #[test]
     fn test_variant_builder_to_list_builder_no_finish() {
         // Create a list builder but never finish it

Reply via email to