Skip to content

Commit 8b2ff8a

Browse files
committed
feat(sdk): Rewrite LinkedChunk::replace_gap_at.
This patch rewrites `LinkedChunk::replace_gap_at`. Instead of inserting new items on the _previous_ chunk of the gap and doing all the stuff here, a new items chunk is created _after_ the gap (where items are pushed), to finally unlink and remove the gap. First off, it removes an `unwrap`. Second, if the previous chunk was an items chunk, and had free space, the items would have been added in there, which is not the intended behaviour. The tests have been updated accordingly.
1 parent 6b754ac commit 8b2ff8a

File tree

2 files changed

+25
-27
lines changed

2 files changed

+25
-27
lines changed

crates/matrix-sdk/src/event_cache/linked_chunk.rs

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -270,40 +270,38 @@ impl<Item, Gap, const CAP: usize> LinkedChunk<Item, Gap, CAP> {
270270

271271
debug_assert!(chunk.is_first_chunk().not(), "A gap cannot be the first chunk");
272272

273-
let (previous, number_of_items) = match &mut chunk.content {
273+
let (maybe_last_chunk_ptr, number_of_items) = match &mut chunk.content {
274274
ChunkContent::Gap(..) => {
275275
let items = items.into_iter();
276276
let number_of_items = items.len();
277277

278-
// Find the previous chunk…
279-
//
280-
// SAFETY: `unwrap` is safe because we are ensured `chunk` is not the first
281-
// chunk, so a previous chunk always exists.
282-
let previous = chunk.previous_mut().unwrap();
278+
let last_inserted_chunk = chunk
279+
// Insert a new items chunk…
280+
.insert_next(Chunk::new_items_leaked(
281+
chunk_identifier_generator.generate_next().unwrap(),
282+
))
283+
// … and insert the items.
284+
.push_items(items, &chunk_identifier_generator);
283285

284-
// … and insert the items on it.
285-
(previous.push_items(items, &chunk_identifier_generator), number_of_items)
286+
(
287+
last_inserted_chunk.is_last_chunk().then(|| last_inserted_chunk.as_ptr()),
288+
number_of_items,
289+
)
286290
}
287291
ChunkContent::Items(..) => {
288292
return Err(LinkedChunkError::ChunkIsItems { identifier: chunk_identifier })
289293
}
290294
};
291295

292-
// Get the pointer to `chunk` via `previous`.
293-
//
294-
// SAFETY: `unwrap` is safe because we are ensured the next of the previous
295-
// chunk is `chunk` itself.
296-
chunk_ptr = previous.next.unwrap();
297-
298-
// Get the pointer to the `previous` via `chunk`.
299-
let previous_ptr = chunk.previous;
300-
301296
// Now that new items have been pushed, we can unlink the gap chunk.
302297
chunk.unlink();
303298

299+
// Get the pointer to `chunk`.
300+
chunk_ptr = chunk.as_ptr();
301+
304302
// Update `self.last` if the gap chunk was the last chunk.
305-
if chunk.is_last_chunk() {
306-
self.last = previous_ptr;
303+
if let Some(last_chunk_ptr) = maybe_last_chunk_ptr {
304+
self.last = Some(last_chunk_ptr);
307305
}
308306

309307
self.length += number_of_items;
@@ -1432,10 +1430,10 @@ mod tests {
14321430
#[test]
14331431
fn test_replace_gap_at() -> Result<(), LinkedChunkError> {
14341432
let mut linked_chunk = LinkedChunk::<char, (), 3>::new();
1435-
linked_chunk.push_items_back(['a', 'b', 'c']);
1433+
linked_chunk.push_items_back(['a', 'b']);
14361434
linked_chunk.push_gap_back(());
1437-
linked_chunk.push_items_back(['l', 'm', 'n']);
1438-
assert_items_eq!(linked_chunk, ['a', 'b', 'c'] [-] ['l', 'm', 'n']);
1435+
linked_chunk.push_items_back(['l', 'm']);
1436+
assert_items_eq!(linked_chunk, ['a', 'b'] [-] ['l', 'm']);
14391437

14401438
// Replace a gap in the middle of the linked chunk.
14411439
{
@@ -1445,7 +1443,7 @@ mod tests {
14451443
linked_chunk.replace_gap_at(['d', 'e', 'f', 'g', 'h'], gap_identifier)?;
14461444
assert_items_eq!(
14471445
linked_chunk,
1448-
['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm', 'n']
1446+
['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm']
14491447
);
14501448
}
14511449

@@ -1454,7 +1452,7 @@ mod tests {
14541452
linked_chunk.push_gap_back(());
14551453
assert_items_eq!(
14561454
linked_chunk,
1457-
['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm', 'n'] [-]
1455+
['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm'] [-]
14581456
);
14591457

14601458
let gap_identifier = linked_chunk.chunk_identifier(Chunk::is_gap).unwrap();
@@ -1463,11 +1461,11 @@ mod tests {
14631461
linked_chunk.replace_gap_at(['w', 'x', 'y', 'z'], gap_identifier)?;
14641462
assert_items_eq!(
14651463
linked_chunk,
1466-
['a', 'b', 'c'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm', 'n'] ['w', 'x', 'y'] ['z']
1464+
['a', 'b'] ['d', 'e', 'f'] ['g', 'h'] ['l', 'm'] ['w', 'x', 'y'] ['z']
14671465
);
14681466
}
14691467

1470-
assert_eq!(linked_chunk.len(), 15);
1468+
assert_eq!(linked_chunk.len(), 13);
14711469

14721470
Ok(())
14731471
}

crates/matrix-sdk/src/event_cache/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ mod tests {
764764
use matrix_sdk_test::{async_test, sync_timeline_event};
765765
use ruma::room_id;
766766

767-
use super::{store::TimelineEntry, EventCacheError};
767+
use super::EventCacheError;
768768
use crate::{event_cache::store::PaginationToken, test_utils::logged_in_client};
769769

770770
#[async_test]

0 commit comments

Comments
 (0)