@@ -356,8 +356,19 @@ impl UpdateToVectorDiff {
356356 }
357357 }
358358
359- Update :: RemoveItem { at } => {
360- todo ! ( )
359+ Update :: RemoveItem { at : position } => {
360+ let ( offset, ( _chunk_index, chunk_length) ) = self . map_to_offset ( position) ;
361+
362+ // Remove one item to the chunk in `self.chunks`.
363+ * chunk_length -= 1 ;
364+
365+ // See `reattaching` to learn more.
366+ if reattaching {
367+ continue ;
368+ }
369+
370+ // Let's emit a `VectorDiff::Remove`.
371+ diffs. push ( VectorDiff :: Remove { index : offset } ) ;
361372 }
362373
363374 Update :: DetachLastItems { at : position } => {
@@ -456,6 +467,9 @@ mod tests {
456467 match diff {
457468 VectorDiff :: Insert { index, value } => accumulator. insert ( index, value) ,
458469 VectorDiff :: Append { values } => accumulator. append ( values) ,
470+ VectorDiff :: Remove { index } => {
471+ accumulator. remove ( index) ;
472+ }
459473 diff => unimplemented ! ( "{diff:?}" ) ,
460474 }
461475 }
@@ -599,15 +613,77 @@ mod tests {
599613 & [ VectorDiff :: Insert { index : 0 , value : 'm' } ] ,
600614 ) ;
601615
616+ let removed_item = linked_chunk
617+ . remove_item_at ( linked_chunk. item_position ( |item| * item == 'c' ) . unwrap ( ) )
618+ . unwrap ( ) ;
619+ assert_eq ! ( removed_item, 'c' ) ;
620+ assert_items_eq ! (
621+ linked_chunk,
622+ [ 'm' , 'a' , 'w' ] [ 'x' ] [ 'y' , 'z' , 'b' ] [ 'd' ] [ 'i' , 'j' , 'k' ] [ 'l' ] [ 'e' , 'f' , 'g' ] [ 'h' ]
623+ ) ;
624+
625+ // From an `ObservableVector` point of view, it would look like:
626+ //
627+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
628+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
629+ // | m | a | w | x | y | z | b | d | i | j | k | l | e | f | g | h |
630+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
631+ // ^
632+ // |
633+ // `c` has been removed
634+ apply_and_assert_eq ( & mut accumulator, as_vector. take ( ) , & [ VectorDiff :: Remove { index : 7 } ] ) ;
635+
636+ let removed_item = linked_chunk
637+ . remove_item_at ( linked_chunk. item_position ( |item| * item == 'z' ) . unwrap ( ) )
638+ . unwrap ( ) ;
639+ assert_eq ! ( removed_item, 'z' ) ;
640+ assert_items_eq ! (
641+ linked_chunk,
642+ [ 'm' , 'a' , 'w' ] [ 'x' ] [ 'y' , 'b' ] [ 'd' ] [ 'i' , 'j' , 'k' ] [ 'l' ] [ 'e' , 'f' , 'g' ] [ 'h' ]
643+ ) ;
644+
645+ // From an `ObservableVector` point of view, it would look like:
646+ //
647+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
648+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
649+ // | m | a | w | x | y | b | d | i | j | k | l | e | f | g | h |
650+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
651+ // ^
652+ // |
653+ // `z` has been removed
654+ apply_and_assert_eq ( & mut accumulator, as_vector. take ( ) , & [ VectorDiff :: Remove { index : 5 } ] ) ;
655+
656+ linked_chunk
657+ . insert_items_at ( [ 'z' ] , linked_chunk. item_position ( |item| * item == 'h' ) . unwrap ( ) )
658+ . unwrap ( ) ;
659+
660+ assert_items_eq ! (
661+ linked_chunk,
662+ [ 'm' , 'a' , 'w' ] [ 'x' ] [ 'y' , 'b' ] [ 'd' ] [ 'i' , 'j' , 'k' ] [ 'l' ] [ 'e' , 'f' , 'g' ] [ 'z' , 'h' ]
663+ ) ;
664+
665+ // From an `ObservableVector` point of view, it would look like:
666+ //
667+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
668+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
669+ // | m | a | w | x | y | b | d | i | j | k | l | e | f | g | z | h |
670+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
671+ // ^^^^
672+ // |
673+ // new!
674+ apply_and_assert_eq (
675+ & mut accumulator,
676+ as_vector. take ( ) ,
677+ & [ VectorDiff :: Insert { index : 14 , value : 'z' } ] ,
678+ ) ;
679+
602680 drop ( linked_chunk) ;
603681 assert ! ( as_vector. take( ) . is_empty( ) ) ;
604682
605683 // Finally, ensure the “reconstitued” vector is the one expected.
606684 assert_eq ! (
607685 accumulator,
608- vector![
609- 'm' , 'a' , 'w' , 'x' , 'y' , 'z' , 'b' , 'c' , 'd' , 'i' , 'j' , 'k' , 'l' , 'e' , 'f' , 'g' , 'h'
610- ]
686+ vector![ 'm' , 'a' , 'w' , 'x' , 'y' , 'b' , 'd' , 'i' , 'j' , 'k' , 'l' , 'e' , 'f' , 'g' , 'z' , 'h' ]
611687 ) ;
612688 }
613689
@@ -643,6 +719,7 @@ mod tests {
643719 PushItems { items : Vec < char > } ,
644720 PushGap ,
645721 ReplaceLastGap { items : Vec < char > } ,
722+ RemoveItem { item : char } ,
646723 }
647724
648725 fn as_vector_operation_strategy ( ) -> impl Strategy < Value = AsVectorOperation > {
@@ -654,13 +731,16 @@ mod tests {
654731
655732 1 => prop:: collection:: vec( prop:: char :: ranges( vec![ 'a' ..='z' , 'A' ..='Z' ] . into( ) ) , 0 ..=25 )
656733 . prop_map( |items| AsVectorOperation :: ReplaceLastGap { items } ) ,
734+
735+ 1 => prop:: char :: ranges( vec![ 'a' ..='z' , 'A' ..='Z' ] . into( ) )
736+ . prop_map( |item| AsVectorOperation :: RemoveItem { item } ) ,
657737 ]
658738 }
659739
660740 proptest ! {
661741 #[ test]
662742 fn as_vector_is_correct(
663- operations in prop:: collection:: vec( as_vector_operation_strategy( ) , 10 ..=50 )
743+ operations in prop:: collection:: vec( as_vector_operation_strategy( ) , 50 ..=200 )
664744 ) {
665745 let mut linked_chunk = LinkedChunk :: <10 , char , ( ) >:: new_with_update_history( ) ;
666746 let mut as_vector = linked_chunk. as_vector( ) . unwrap( ) ;
@@ -683,7 +763,17 @@ mod tests {
683763 continue ;
684764 } ;
685765
686- linked_chunk. replace_gap_at( items, gap_identifier) . unwrap( ) ;
766+ linked_chunk. replace_gap_at( items, gap_identifier) . expect( "Failed to replace a gap" ) ;
767+ }
768+
769+ AsVectorOperation :: RemoveItem { item: expected_item } => {
770+ let Some ( position) = linked_chunk
771+ . items( ) . find_map( |( position, item) | ( * item == expected_item) . then_some( position) )
772+ else {
773+ continue ;
774+ } ;
775+
776+ linked_chunk. remove_item_at( position) . expect( "Failed to remove an item" ) ;
687777 }
688778 }
689779 }
@@ -699,6 +789,9 @@ mod tests {
699789
700790 vector_from_diffs. append( & mut values) ;
701791 }
792+ VectorDiff :: Remove { index } => {
793+ vector_from_diffs. remove( index) ;
794+ }
702795 _ => unreachable!( ) ,
703796 }
704797 }
0 commit comments