@@ -306,15 +306,33 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
306306 /// - String length exceeds `u32::MAX`
307307 #[ inline]
308308 pub fn append_value ( & mut self , value : impl AsRef < T :: Native > ) {
309+ self . try_append_value ( value) . unwrap ( )
310+ }
311+
312+ /// Appends a value into the builder
313+ ///
314+ /// # Errors
315+ ///
316+ /// Returns an error if:
317+ /// - String buffer count exceeds `u32::MAX`
318+ /// - String length exceeds `u32::MAX`
319+ #[ inline]
320+ pub fn try_append_value ( & mut self , value : impl AsRef < T :: Native > ) -> Result < ( ) , ArrowError > {
309321 let v: & [ u8 ] = value. as_ref ( ) . as_ref ( ) ;
310- let length: u32 = v. len ( ) . try_into ( ) . unwrap ( ) ;
322+ let length: u32 = v. len ( ) . try_into ( ) . map_err ( |_| {
323+ ArrowError :: InvalidArgumentError ( format ! (
324+ "String length {} exceeds u32::MAX" ,
325+ v. len( )
326+ ) )
327+ } ) ?;
328+
311329 if length <= MAX_INLINE_VIEW_LEN {
312330 let mut view_buffer = [ 0 ; 16 ] ;
313331 view_buffer[ 0 ..4 ] . copy_from_slice ( & length. to_le_bytes ( ) ) ;
314332 view_buffer[ 4 ..4 + v. len ( ) ] . copy_from_slice ( v) ;
315333 self . views_buffer . push ( u128:: from_le_bytes ( view_buffer) ) ;
316334 self . null_buffer_builder . append_non_null ( ) ;
317- return ;
335+ return Ok ( ( ) ) ;
318336 }
319337
320338 // Deduplication if:
@@ -339,7 +357,7 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
339357 self . views_buffer . push ( self . views_buffer [ * idx] ) ;
340358 self . null_buffer_builder . append_non_null ( ) ;
341359 self . string_tracker = Some ( ( ht, hasher) ) ;
342- return ;
360+ return Ok ( ( ) ) ;
343361 }
344362 Entry :: Vacant ( vacant) => {
345363 // o.w. we insert the (string hash -> view index)
@@ -356,17 +374,40 @@ impl<T: ByteViewType + ?Sized> GenericByteViewBuilder<T> {
356374 let to_reserve = v. len ( ) . max ( self . block_size . next_size ( ) as usize ) ;
357375 self . in_progress . reserve ( to_reserve) ;
358376 } ;
359- let offset = self . in_progress . len ( ) as u32 ;
377+ let offset: u32 = self . in_progress . len ( ) . try_into ( ) . map_err ( |_| {
378+ ArrowError :: InvalidArgumentError ( format ! (
379+ "In-progress buffer length {} exceeds u32::MAX" ,
380+ self . in_progress. len( )
381+ ) )
382+ } ) ?;
360383 self . in_progress . extend_from_slice ( v) ;
361384
385+ let prefix = v. get ( 0 ..4 )
386+ . and_then ( |slice| slice. try_into ( ) . ok ( ) )
387+ . map ( u32:: from_le_bytes)
388+ . ok_or_else ( || {
389+ ArrowError :: InvalidArgumentError (
390+ "String must be at least 4 bytes for non-inline view" . to_string ( )
391+ )
392+ } ) ?;
393+
394+ let buffer_index: u32 = self . completed . len ( ) . try_into ( ) . map_err ( |_| {
395+ ArrowError :: InvalidArgumentError ( format ! (
396+ "Buffer count {} exceeds u32::MAX" ,
397+ self . completed. len( )
398+ ) )
399+ } ) ?;
400+
362401 let view = ByteView {
363402 length,
364- prefix : u32 :: from_le_bytes ( v [ 0 .. 4 ] . try_into ( ) . unwrap ( ) ) ,
365- buffer_index : self . completed . len ( ) as u32 ,
403+ prefix,
404+ buffer_index,
366405 offset,
367406 } ;
368407 self . views_buffer . push ( view. into ( ) ) ;
369408 self . null_buffer_builder . append_non_null ( ) ;
409+
410+ Ok ( ( ) )
370411 }
371412
372413 /// Append an `Option` value into the builder
0 commit comments