@@ -557,15 +557,18 @@ pub trait InnerNode<const PREFIX_LEN: usize>:
557557/// Marker type for [`InnerNodeBuilder`]: no children have been added yet.
558558pub struct NoChild ;
559559
560- /// Marker type for [`InnerNodeBuilder`]: at least one child has been added.
560+ /// Marker type for [`InnerNodeBuilder`]: exactly one child has been added.
561+ pub struct HasOneChild ;
562+
563+ /// Marker type for [`InnerNodeBuilder`]: at least two children have been added.
561564pub struct HasChild ;
562565
563- /// Typestate builder for inner nodes that enforces the non-empty invariant.
566+ /// Typestate builder for inner nodes that enforces the two-child minimum
567+ /// invariant.
564568///
565569/// The only way to call [`build`][InnerNodeBuilder::build] is to first add at
566- /// least one child via
567- /// [`write_child`][InnerNodeBuilder::write_child]. This is checked at
568- /// compile time via the `S` typestate parameter.
570+ /// least two children via [`write_child`][InnerNodeBuilder::write_child]. This
571+ /// is checked at compile time via the `S` typestate parameter.
569572///
570573/// Obtain a builder via [`InnerNodeCommon::builder`].
571574#[ expect( clippy:: type_complexity) ]
@@ -578,8 +581,27 @@ impl<K, V, const PREFIX_LEN: usize, N> InnerNodeBuilder<K, V, PREFIX_LEN, N, NoC
578581where
579582 N : InnerNodeCommon < K , V , PREFIX_LEN > ,
580583{
581- /// Add the first child, transitioning the builder to the [`HasChild`] state
582- /// and enabling [`build`][InnerNodeBuilder::build].
584+ /// Add the first child, transitioning the builder to the [`HasOneChild`]
585+ /// state.
586+ pub fn write_child (
587+ mut self ,
588+ key_byte : u8 ,
589+ child : OpaqueNodePtr < K , V , PREFIX_LEN > ,
590+ ) -> InnerNodeBuilder < K , V , PREFIX_LEN , N , HasOneChild > {
591+ self . node . write_child ( key_byte, child) ;
592+ InnerNodeBuilder {
593+ node : self . node ,
594+ _state : PhantomData ,
595+ }
596+ }
597+ }
598+
599+ impl < K , V , const PREFIX_LEN : usize , N > InnerNodeBuilder < K , V , PREFIX_LEN , N , HasOneChild >
600+ where
601+ N : InnerNodeCommon < K , V , PREFIX_LEN > ,
602+ {
603+ /// Add the second child, transitioning the builder to the [`HasChild`]
604+ /// state and enabling [`build`][InnerNodeBuilder::build].
583605 pub fn write_child (
584606 mut self ,
585607 key_byte : u8 ,
@@ -598,7 +620,31 @@ impl<K, V, const PREFIX_LEN: usize>
598620{
599621 /// Add the first child to the node without bounds check or order.
600622 ///
601- /// This function transitions the build to the [`HasChild`] state and
623+ /// This function transitions the builder to the [`HasOneChild`] state.
624+ ///
625+ /// # Safety
626+ /// - This functions assumes that the write is gonna be inbound (i.e the
627+ /// check for a full node is done previously to the call of this function)
628+ pub unsafe fn write_child_unchecked (
629+ mut self ,
630+ key_byte : u8 ,
631+ child : OpaqueNodePtr < K , V , PREFIX_LEN > ,
632+ ) -> InnerNodeBuilder < K , V , PREFIX_LEN , InnerNode4 < K , V , PREFIX_LEN > , HasOneChild > {
633+ // SAFETY: Covered by function safety requirements
634+ unsafe { self . node . write_child_unchecked ( key_byte, child) } ;
635+ InnerNodeBuilder {
636+ node : self . node ,
637+ _state : PhantomData ,
638+ }
639+ }
640+ }
641+
642+ impl < K , V , const PREFIX_LEN : usize >
643+ InnerNodeBuilder < K , V , PREFIX_LEN , InnerNode4 < K , V , PREFIX_LEN > , HasOneChild >
644+ {
645+ /// Add the second child to the node without bounds check or order.
646+ ///
647+ /// This function transitions the builder to the [`HasChild`] state and
602648 /// enabling [`build`][InnerNodeBuilder::build].
603649 ///
604650 /// # Safety
@@ -897,15 +943,19 @@ mod tests {
897943
898944 let n4 = InnerNode4 :: < Box < [ u8 ] > , ( ) , 16 > :: builder ( & [ ] , 0 )
899945 . write_child ( 0 , leaf_ptr)
946+ . write_child ( 1 , leaf_ptr)
900947 . build ( ) ;
901948 let n16 = InnerNode4 :: < Box < [ u8 ] > , ( ) , 16 > :: builder ( & [ ] , 0 )
902949 . write_child ( 0 , leaf_ptr)
950+ . write_child ( 1 , leaf_ptr)
903951 . build ( ) ;
904952 let n48 = InnerNode4 :: < Box < [ u8 ] > , ( ) , 16 > :: builder ( & [ ] , 0 )
905953 . write_child ( 0 , leaf_ptr)
954+ . write_child ( 1 , leaf_ptr)
906955 . build ( ) ;
907956 let n256 = InnerNode4 :: < Box < [ u8 ] > , ( ) , 16 > :: builder ( & [ ] , 0 )
908957 . write_child ( 0 , leaf_ptr)
958+ . write_child ( 1 , leaf_ptr)
909959 . build ( ) ;
910960
911961 let n4_ptr = const_addr ( & n4 as * const InnerNode4 < Box < [ u8 ] > , ( ) , 16 > ) ;
@@ -934,12 +984,15 @@ mod tests {
934984 . map ( |leaf| NodePtr :: from ( leaf) . to_opaque ( ) )
935985 . collect ( ) ;
936986
937- let mut node = N :: builder ( & [ ] , 0 ) . write_child ( 0 , leaf_pointers[ 0 ] ) . build ( ) ;
987+ let mut node = N :: builder ( & [ ] , 0 )
988+ . write_child ( 0 , leaf_pointers[ 0 ] )
989+ . write_child ( 1 , leaf_pointers[ 1 ] )
990+ . build ( ) ;
938991
939992 assert ! ( !node. is_full( ) ) ;
940993
941- for ( idx, leaf_pointer) in leaf_pointers[ 1 ..] . iter ( ) . copied ( ) . enumerate ( ) {
942- node. write_child ( u8:: try_from ( idx + 1 ) . unwrap ( ) , leaf_pointer) ;
994+ for ( idx, leaf_pointer) in leaf_pointers[ 2 ..] . iter ( ) . copied ( ) . enumerate ( ) {
995+ node. write_child ( u8:: try_from ( idx + 2 ) . unwrap ( ) , leaf_pointer) ;
943996 }
944997
945998 for ( idx, leaf_pointer) in leaf_pointers. iter ( ) . copied ( ) . enumerate ( ) {
@@ -965,12 +1018,15 @@ mod tests {
9651018 . map ( |leaf| NodePtr :: from ( leaf) . to_opaque ( ) )
9661019 . collect ( ) ;
9671020
968- let mut node = N :: builder ( & [ ] , 0 ) . write_child ( 0 , leaf_pointers[ 0 ] ) . build ( ) ;
1021+ let mut node = N :: builder ( & [ ] , 0 )
1022+ . write_child ( 0 , leaf_pointers[ 0 ] )
1023+ . write_child ( 1 , leaf_pointers[ 1 ] )
1024+ . build ( ) ;
9691025
9701026 assert ! ( !node. is_full( ) ) ;
9711027
972- for ( idx, leaf_pointer) in leaf_pointers[ 1 ..] . iter ( ) . copied ( ) . enumerate ( ) {
973- node. write_child ( u8:: try_from ( idx + 1 ) . unwrap ( ) , leaf_pointer) ;
1028+ for ( idx, leaf_pointer) in leaf_pointers[ 2 ..] . iter ( ) . copied ( ) . enumerate ( ) {
1029+ node. write_child ( u8:: try_from ( idx + 2 ) . unwrap ( ) , leaf_pointer) ;
9741030 }
9751031
9761032 for ( idx, leaf_pointer) in leaf_pointers. iter ( ) . copied ( ) . enumerate ( ) {
@@ -1005,10 +1061,13 @@ mod tests {
10051061 . map ( |leaf| NodePtr :: from ( leaf) . to_opaque ( ) )
10061062 . collect ( ) ;
10071063
1008- let mut node = N :: builder ( & [ ] , 0 ) . write_child ( 0 , leaf_pointers[ 0 ] ) . build ( ) ;
1064+ let mut node = N :: builder ( & [ ] , 0 )
1065+ . write_child ( 0 , leaf_pointers[ 0 ] )
1066+ . write_child ( 1 , leaf_pointers[ 1 ] )
1067+ . build ( ) ;
10091068
1010- for ( idx, leaf_pointer) in leaf_pointers[ 1 ..] . iter ( ) . copied ( ) . enumerate ( ) {
1011- node. write_child ( u8:: try_from ( idx + 1 ) . unwrap ( ) , leaf_pointer) ;
1069+ for ( idx, leaf_pointer) in leaf_pointers[ 2 ..] . iter ( ) . copied ( ) . enumerate ( ) {
1070+ node. write_child ( u8:: try_from ( idx + 2 ) . unwrap ( ) , leaf_pointer) ;
10121071 }
10131072
10141073 let shrunk_node = node. shrink ( ) ;
@@ -1039,10 +1098,13 @@ mod tests {
10391098 . map ( |leaf| NodePtr :: from ( leaf) . to_opaque ( ) )
10401099 . collect ( ) ;
10411100
1042- let mut node = N :: builder ( & [ ] , 0 ) . write_child ( 0 , leaf_pointers[ 0 ] ) . build ( ) ;
1101+ let mut node = N :: builder ( & [ ] , 0 )
1102+ . write_child ( 0 , leaf_pointers[ 0 ] )
1103+ . write_child ( 1 , leaf_pointers[ 1 ] )
1104+ . build ( ) ;
10431105
1044- for ( idx, leaf_pointer) in leaf_pointers[ 1 ..] . iter ( ) . copied ( ) . enumerate ( ) {
1045- node. write_child ( u8:: try_from ( idx + 1 ) . unwrap ( ) , leaf_pointer) ;
1106+ for ( idx, leaf_pointer) in leaf_pointers[ 2 ..] . iter ( ) . copied ( ) . enumerate ( ) {
1107+ node. write_child ( u8:: try_from ( idx + 2 ) . unwrap ( ) , leaf_pointer) ;
10461108 }
10471109
10481110 assert_eq ! ( node. header( ) . num_children( ) , num_children) ;
0 commit comments