1
1
//! This module contains fragments implementation.
2
- use super :: { Key , VDiff , VNode , VTag } ;
2
+ use super :: { Key , VDiff , VNode , VText } ;
3
3
use crate :: html:: { AnyScope , NodeRef } ;
4
4
use cfg_if:: cfg_if;
5
5
use std:: collections:: HashMap ;
@@ -160,53 +160,18 @@ impl VList {
160
160
next_sibling
161
161
}
162
162
163
- /// Diff and patch fully keyed child lists.
164
- ///
165
- /// Optimized for node addition or removal from either end of the list and small changes in the
166
- /// middle.
163
+ /// Diff and patch fully keyed child lists
167
164
fn apply_keyed (
168
165
parent_scope : & AnyScope ,
169
166
parent : & Element ,
170
167
mut next_sibling : NodeRef ,
171
168
lefts : & mut [ VNode ] ,
172
- mut rights : Vec < VNode > ,
169
+ rights : Vec < VNode > ,
173
170
) -> NodeRef {
174
- macro_rules! map_keys {
175
- ( $src: expr) => {
176
- $src. iter( )
177
- . map( |v| v. key( ) . expect( "unkeyed child in fully keyed list" ) )
178
- . collect:: <Vec <Key >>( )
179
- } ;
180
- }
181
- let lefts_keys = map_keys ! ( lefts) ;
182
- let rights_keys = map_keys ! ( rights) ;
183
-
184
- /// Find the first differing key in 2 iterators
185
- fn diff_i < ' a , ' b > (
186
- a : impl Iterator < Item = & ' a Key > ,
187
- b : impl Iterator < Item = & ' b Key > ,
188
- ) -> usize {
189
- a. zip ( b) . take_while ( |( a, b) | a == b) . count ( )
190
- }
191
-
192
- // Find first key mismatch from the front
193
- let from_start = diff_i ( lefts_keys. iter ( ) , rights_keys. iter ( ) ) ;
194
-
195
- if from_start == std:: cmp:: min ( lefts. len ( ) , rights. len ( ) ) {
196
- // No key changes
197
- return Self :: apply_unkeyed ( parent_scope, parent, next_sibling, lefts, rights) ;
198
- }
199
-
200
- // Find first key mismatch from the back
201
- let from_end = diff_i (
202
- lefts_keys[ from_start..] . iter ( ) . rev ( ) ,
203
- rights_keys[ from_start..] . iter ( ) . rev ( ) ,
204
- ) ;
205
-
206
171
macro_rules! apply {
207
172
( $l: expr, $r: expr) => {
208
173
test_log!( "patching: {:?} -> {:?}" , $r, $l) ;
209
- apply!( std :: mem :: take ( $r ) . into( ) => $l) ;
174
+ apply!( $r . into( ) => $l) ;
210
175
} ;
211
176
( $l: expr) => {
212
177
test_log!( "adding: {:?}" , $l) ;
@@ -221,29 +186,33 @@ impl VList {
221
186
} ;
222
187
}
223
188
224
- // Diff matching children at the end
225
- let lefts_to = lefts_keys. len ( ) - from_end;
226
- let rights_to = rights_keys. len ( ) - from_end;
227
- for ( l, r) in lefts[ lefts_to..]
228
- . iter_mut ( )
229
- . rev ( )
230
- . zip ( rights[ rights_to..] . iter_mut ( ) . rev ( ) )
231
- {
232
- apply ! ( l, r) ;
189
+ // Perform backwards iteration, until a key mismatch or depleted iterator
190
+ let mut l_it = lefts. iter_mut ( ) . rev ( ) . peekable ( ) ;
191
+ let mut r_it = rights. into_iter ( ) . rev ( ) . peekable ( ) ;
192
+ loop {
193
+ let l_next = l_it. peek ( ) ;
194
+ let r_next = r_it. peek ( ) ;
195
+
196
+ match ( l_next, r_next) {
197
+ ( Some ( l_next) , Some ( r_next) ) if l_next. key_ref ( ) == r_next. key_ref ( ) => {
198
+ apply ! ( l_it. next( ) . unwrap( ) , r_it. next( ) . unwrap( ) ) ;
199
+ }
200
+ _ => break ,
201
+ }
233
202
}
234
203
235
- // Diff mismatched children in the middle
236
- let mut rights_diff: HashMap < Key , & mut VNode > = rights_keys[ from_start..rights_to]
237
- . iter ( )
238
- . zip ( rights[ from_start..rights_to] . iter_mut ( ) )
239
- . map ( |( k, v) | ( k. clone ( ) , v) )
204
+ // Collect the rest of rights into a map for quick lookup
205
+ let mut r_diff: HashMap < Key , VNode > = r_it
206
+ . map ( |n| ( n. key ( ) . expect ( "unkeyed child in fully keyed VList" ) , n) )
240
207
. collect ( ) ;
241
- for ( l_k, l) in lefts_keys[ from_start..lefts_to]
242
- . iter ( )
243
- . rev ( )
244
- . zip ( lefts[ from_start..lefts_to] . iter_mut ( ) . rev ( ) )
245
- {
246
- match rights_diff. remove ( l_k) {
208
+
209
+ // Continue iteration of lefts
210
+ for l in l_it {
211
+ match r_diff. remove (
212
+ l. key_ref ( )
213
+ . as_ref ( )
214
+ . expect ( "unkeyed child in fully keyed VList" ) ,
215
+ ) {
247
216
// Reorder and diff any existing children
248
217
Some ( r) => {
249
218
test_log ! ( "moving as next: {:?}" , r) ;
@@ -258,20 +227,11 @@ impl VList {
258
227
}
259
228
260
229
// Remove any extra rights
261
- for ( _, r) in rights_diff . drain ( ) {
230
+ for ( _, mut r) in r_diff . drain ( ) {
262
231
test_log ! ( "removing: {:?}" , r) ;
263
232
r. detach ( parent) ;
264
233
}
265
234
266
- // Diff matching children at the start
267
- for ( l, r) in lefts[ ..from_start]
268
- . iter_mut ( )
269
- . rev ( )
270
- . zip ( rights[ ..from_start] . iter_mut ( ) . rev ( ) )
271
- {
272
- apply ! ( l, r) ;
273
- }
274
-
275
235
next_sibling
276
236
}
277
237
}
@@ -302,10 +262,8 @@ impl VDiff for VList {
302
262
if self . children . is_empty ( ) {
303
263
// Without a placeholder the next element becomes first
304
264
// and corrupts the order of rendering
305
- // We use empty span element to stake out a place
306
- let mut placeholder = VTag :: new ( "span" ) ;
307
- placeholder. key = Some ( "__placeholder" . into ( ) ) ;
308
- self . children = vec ! [ placeholder. into( ) ] ;
265
+ // We use empty text element to stake out a place
266
+ self . add_child ( VText :: new ( "" ) . into ( ) ) ;
309
267
}
310
268
311
269
let lefts = & mut self . children ;
0 commit comments