1414 * limitations under the License.
1515 */
1616
17- extern crate smallvec ;
18-
17+ # [ cfg ( feature = "no_std" ) ]
18+ use alloc :: { vec , vec :: Vec } ;
1919use core:: cmp:: max;
2020use core:: iter:: { DoubleEndedIterator , ExactSizeIterator } ;
2121use core:: marker:: PhantomData ;
2222use core:: ptr:: write_bytes;
23- use core:: slice:: from_raw_parts;
24- #[ cfg( feature = "no_std" ) ]
25- use alloc:: { vec, vec:: Vec } ;
2623
27- use crate :: endian_scalar:: { emplace_scalar, read_scalar_at } ;
24+ use crate :: endian_scalar:: emplace_scalar;
2825use crate :: primitives:: * ;
2926use crate :: push:: { Push , PushAlignment } ;
27+ use crate :: read_scalar;
3028use crate :: table:: Table ;
31- use crate :: vector:: { SafeSliceAccess , Vector } ;
29+ use crate :: vector:: Vector ;
3230use crate :: vtable:: { field_index_to_field_offset, VTable } ;
3331use crate :: vtable_writer:: VTableWriter ;
3432
35- pub const N_SMALLVEC_STRING_VECTOR_CAPACITY : usize = 16 ;
36-
3733#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
3834struct FieldLoc {
3935 off : UOffsetT ,
@@ -121,6 +117,8 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
121117 {
122118 let to_clear = self . owned_buf . len ( ) - self . head ;
123119 let ptr = ( & mut self . owned_buf [ self . head ..] ) . as_mut_ptr ( ) ;
120+ // Safety:
121+ // Verified ptr is valid for `to_clear` above
124122 unsafe {
125123 write_bytes ( ptr, 0 , to_clear) ;
126124 }
@@ -153,7 +151,9 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
153151 self . make_space ( sz) ;
154152 {
155153 let ( dst, rest) = ( & mut self . owned_buf [ self . head ..] ) . split_at_mut ( sz) ;
156- x. push ( dst, rest) ;
154+ // Safety:
155+ // Called make_space above
156+ unsafe { x. push ( dst, rest. len ( ) ) } ;
157157 }
158158 WIPOffset :: new ( self . used_space ( ) as UOffsetT )
159159 }
@@ -309,73 +309,32 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
309309 WIPOffset :: new ( self . used_space ( ) as UOffsetT )
310310 }
311311
312- /// Create a vector by memcpy'ing. This is much faster than calling
313- /// `create_vector`, but the underlying type must be represented as
314- /// little-endian on the host machine. This property is encoded in the
315- /// type system through the SafeSliceAccess trait. The following types are
316- /// always safe, on any platform: bool, u8, i8, and any
317- /// FlatBuffers-generated struct.
318- #[ inline]
319- pub fn create_vector_direct < ' a : ' b , ' b , T : SafeSliceAccess + Push + Sized + ' b > (
320- & ' a mut self ,
321- items : & ' b [ T ] ,
322- ) -> WIPOffset < Vector < ' fbb , T > > {
323- self . assert_not_nested (
324- "create_vector_direct can not be called when a table or vector is under construction" ,
325- ) ;
326- let elem_size = T :: size ( ) ;
327- self . align ( items. len ( ) * elem_size, T :: alignment ( ) . max_of ( SIZE_UOFFSET ) ) ;
328-
329- let bytes = {
330- let ptr = items. as_ptr ( ) as * const T as * const u8 ;
331- unsafe { from_raw_parts ( ptr, items. len ( ) * elem_size) }
332- } ;
333- self . push_bytes_unprefixed ( bytes) ;
334- self . push ( items. len ( ) as UOffsetT ) ;
335-
336- WIPOffset :: new ( self . used_space ( ) as UOffsetT )
337- }
338-
339- /// Create a vector of strings.
340- ///
341- /// Speed-sensitive users may wish to reduce memory usage by creating the
342- /// vector manually: use `start_vector`, `push`, and `end_vector`.
343- #[ inline]
344- pub fn create_vector_of_strings < ' a , ' b > (
345- & ' a mut self ,
346- xs : & ' b [ & ' b str ] ,
347- ) -> WIPOffset < Vector < ' fbb , ForwardsUOffset < & ' fbb str > > > {
348- self . assert_not_nested ( "create_vector_of_strings can not be called when a table or vector is under construction" ) ;
349- // internally, smallvec can be a stack-allocated or heap-allocated vector:
350- // if xs.len() > N_SMALLVEC_STRING_VECTOR_CAPACITY then it will overflow to the heap.
351- let mut offsets: smallvec:: SmallVec < [ WIPOffset < & str > ; N_SMALLVEC_STRING_VECTOR_CAPACITY ] > =
352- smallvec:: SmallVec :: with_capacity ( xs. len ( ) ) ;
353- unsafe {
354- offsets. set_len ( xs. len ( ) ) ;
355- }
356-
357- // note that this happens in reverse, because the buffer is built back-to-front:
358- for ( i, & s) in xs. iter ( ) . enumerate ( ) . rev ( ) {
359- let o = self . create_string ( s) ;
360- offsets[ i] = o;
361- }
362- self . create_vector ( & offsets[ ..] )
363- }
364-
365312 /// Create a vector of Push-able objects.
366313 ///
367314 /// Speed-sensitive users may wish to reduce memory usage by creating the
368315 /// vector manually: use `start_vector`, `push`, and `end_vector`.
369316 #[ inline]
370- pub fn create_vector < ' a : ' b , ' b , T : Push + Copy + ' b > (
317+ pub fn create_vector < ' a : ' b , ' b , T : Push + ' b > (
371318 & ' a mut self ,
372319 items : & ' b [ T ] ,
373320 ) -> WIPOffset < Vector < ' fbb , T :: Output > > {
374321 let elem_size = T :: size ( ) ;
375- self . align ( items. len ( ) * elem_size, T :: alignment ( ) . max_of ( SIZE_UOFFSET ) ) ;
376- for i in ( 0 ..items. len ( ) ) . rev ( ) {
377- self . push ( items[ i] ) ;
322+ let slice_size = items. len ( ) * elem_size;
323+ self . align ( slice_size, T :: alignment ( ) . max_of ( SIZE_UOFFSET ) ) ;
324+ self . ensure_capacity ( slice_size + UOffsetT :: size ( ) ) ;
325+
326+ self . head -= slice_size;
327+ let mut written_len = self . owned_buf . len ( ) - self . head ;
328+
329+ let buf = & mut self . owned_buf [ self . head ..self . head + slice_size] ;
330+ for ( item, out) in items. iter ( ) . zip ( buf. chunks_exact_mut ( elem_size) ) {
331+ written_len -= elem_size;
332+
333+ // Safety:
334+ // Called ensure_capacity and aligned to T above
335+ unsafe { item. push ( out, written_len) } ;
378336 }
337+
379338 WIPOffset :: new ( self . push :: < UOffsetT > ( items. len ( ) as UOffsetT ) . value ( ) )
380339 }
381340
@@ -384,17 +343,18 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
384343 /// Speed-sensitive users may wish to reduce memory usage by creating the
385344 /// vector manually: use `start_vector`, `push`, and `end_vector`.
386345 #[ inline]
387- pub fn create_vector_from_iter < T : Push + Copy > (
346+ pub fn create_vector_from_iter < T : Push > (
388347 & mut self ,
389348 items : impl ExactSizeIterator < Item = T > + DoubleEndedIterator ,
390349 ) -> WIPOffset < Vector < ' fbb , T :: Output > > {
391350 let elem_size = T :: size ( ) ;
392- let len = items . len ( ) ;
393- self . align ( len * elem_size , T :: alignment ( ) . max_of ( SIZE_UOFFSET ) ) ;
351+ self . align ( items . len ( ) * elem_size , T :: alignment ( ) . max_of ( SIZE_UOFFSET ) ) ;
352+ let mut actual = 0 ;
394353 for item in items. rev ( ) {
395354 self . push ( item) ;
355+ actual += 1 ;
396356 }
397- WIPOffset :: new ( self . push :: < UOffsetT > ( len as UOffsetT ) . value ( ) )
357+ WIPOffset :: new ( self . push :: < UOffsetT > ( actual ) . value ( ) )
398358 }
399359
400360 /// Set whether default values are stored.
@@ -443,7 +403,15 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
443403 assert_msg_name : & ' static str ,
444404 ) {
445405 let idx = self . used_space ( ) - tab_revloc. value ( ) as usize ;
446- let tab = Table :: new ( & self . owned_buf [ self . head ..] , idx) ;
406+
407+ // Safety:
408+ // The value of TableFinishedWIPOffset is the offset from the end of owned_buf
409+ // to an SOffsetT pointing to a valid VTable
410+ //
411+ // `self.owned_buf.len() = self.used_space() + self.head`
412+ // `self.owned_buf.len() - tab_revloc = self.used_space() - tab_revloc + self.head`
413+ // `self.owned_buf.len() - tab_revloc = idx + self.head`
414+ let tab = unsafe { Table :: new ( & self . owned_buf [ self . head ..] , idx) } ;
447415 let o = tab. vtable ( ) . get ( slot_byte_loc) as usize ;
448416 assert ! ( o != 0 , "missing required field {}" , assert_msg_name) ;
449417 }
@@ -560,11 +528,15 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
560528 }
561529 }
562530 let new_vt_bytes = & self . owned_buf [ vt_start_pos..vt_end_pos] ;
563- let found = self . written_vtable_revpos . binary_search_by ( |old_vtable_revpos : & UOffsetT | {
564- let old_vtable_pos = self . owned_buf . len ( ) - * old_vtable_revpos as usize ;
565- let old_vtable = VTable :: init ( & self . owned_buf , old_vtable_pos) ;
566- new_vt_bytes. cmp ( old_vtable. as_bytes ( ) )
567- } ) ;
531+ let found = self
532+ . written_vtable_revpos
533+ . binary_search_by ( |old_vtable_revpos : & UOffsetT | {
534+ let old_vtable_pos = self . owned_buf . len ( ) - * old_vtable_revpos as usize ;
535+ // Safety:
536+ // Already written vtables are valid by construction
537+ let old_vtable = unsafe { VTable :: init ( & self . owned_buf , old_vtable_pos) } ;
538+ new_vt_bytes. cmp ( old_vtable. as_bytes ( ) )
539+ } ) ;
568540 let final_vtable_revpos = match found {
569541 Ok ( i) => {
570542 // The new vtable is a duplicate so clear it.
@@ -581,12 +553,22 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
581553 } ;
582554 // Write signed offset from table to its vtable.
583555 let table_pos = self . owned_buf . len ( ) - object_revloc_to_vtable. value ( ) as usize ;
584- let tmp_soffset_to_vt = unsafe { read_scalar_at :: < UOffsetT > ( & self . owned_buf , table_pos) } ;
585- debug_assert_eq ! ( tmp_soffset_to_vt, 0xF0F0_F0F0 ) ;
556+ if cfg ! ( debug_assertions) {
557+ // Safety:
558+ // Verified slice length
559+ let tmp_soffset_to_vt = unsafe {
560+ read_scalar :: < UOffsetT > ( & self . owned_buf [ table_pos..table_pos + SIZE_UOFFSET ] )
561+ } ;
562+ assert_eq ! ( tmp_soffset_to_vt, 0xF0F0_F0F0 ) ;
563+ }
564+
565+ let buf = & mut self . owned_buf [ table_pos..table_pos + SIZE_SOFFSET ] ;
566+ // Safety:
567+ // Verified length of buf above
586568 unsafe {
587569 emplace_scalar :: < SOffsetT > (
588- & mut self . owned_buf [ table_pos..table_pos + SIZE_SOFFSET ] ,
589- final_vtable_revpos as SOffsetT - object_revloc_to_vtable. value ( ) as SOffsetT
570+ buf ,
571+ final_vtable_revpos as SOffsetT - object_revloc_to_vtable. value ( ) as SOffsetT ,
590572 ) ;
591573 }
592574
@@ -624,6 +606,8 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
624606 // finally, zero out the old end data.
625607 {
626608 let ptr = ( & mut self . owned_buf [ ..middle] ) . as_mut_ptr ( ) ;
609+ // Safety:
610+ // ptr is byte aligned and of length middle
627611 unsafe {
628612 write_bytes ( ptr, 0 , middle) ;
629613 }
0 commit comments