Skip to content

Commit

Permalink
fixup! feat(linked chunk): add a way to reconstruct a linked chunk fr…
Browse files Browse the repository at this point in the history
…om its raw representation
  • Loading branch information
bnjbvr committed Nov 26, 2024
1 parent 860d807 commit 1215b8b
Showing 1 changed file with 37 additions and 14 deletions.
51 changes: 37 additions & 14 deletions crates/matrix-sdk-common/src/linked_chunk/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,24 @@ impl<const CAP: usize, Item, Gap> LinkedChunkBuilder<CAP, Item, Gap> {
/// This can be called even if the previous and next chunks have not been
/// added yet. Resolving these chunks will happen at the time of calling
/// [`LinkedChunkBuilder::build()`].
///
/// This will return an error if the number of items is larger than the
/// capacity defined as a generic `CAP` in this struct.
pub fn push_items(
&mut self,
previous: Option<ChunkIdentifier>,
id: ChunkIdentifier,
next: Option<ChunkIdentifier>,
items: impl IntoIterator<Item = Item>,
) {
let chunk = TemporaryChunk {
id,
previous,
next,
content: ChunkContent::Items(items.into_iter().collect()),
};
) -> Result<(), PushItemsChunkError> {
let items: Vec<_> = items.into_iter().collect();
if items.len() > CAP {
return Err(PushItemsChunkError::ChunkTooLarge);
}

let chunk = TemporaryChunk { id, previous, next, content: ChunkContent::Items(items) };
self.chunks.insert(id, chunk);
Ok(())
}

/// Request that the resulting linked chunk will have an update history, as
Expand Down Expand Up @@ -245,6 +249,12 @@ impl<const CAP: usize, Item, Gap> LinkedChunkBuilder<CAP, Item, Gap> {
}
}

#[derive(thiserror::Error, Debug)]
pub enum PushItemsChunkError {
#[error("can't add the chunk because it's too large")]
ChunkTooLarge,
}

#[derive(thiserror::Error, Debug)]
pub enum LinkedChunkBuilderError {
#[error("unable to resolve chunk with id {}", id.index())]
Expand All @@ -269,7 +279,7 @@ mod tests {
use assert_matches::assert_matches;

use super::LinkedChunkBuilder;
use crate::linked_chunk::{ChunkIdentifier, LinkedChunkBuilderError};
use crate::linked_chunk::{ChunkIdentifier, LinkedChunkBuilderError, PushItemsChunkError};

#[test]
fn test_empty() {
Expand All @@ -296,9 +306,9 @@ mod tests {
// The final chunk will contain [cid0 <-> cid1 <-> cid3], in this order.

// Adding chunk cid0.
lcb.push_items(None, cid0, Some(cid1), vec!['a', 'b', 'c']);
lcb.push_items(None, cid0, Some(cid1), vec!['a', 'b', 'c']).unwrap();
// Adding chunk cid3.
lcb.push_items(Some(cid1), cid3, None, vec!['d', 'e']);
lcb.push_items(Some(cid1), cid3, None, vec!['d', 'e']).unwrap();
// Adding chunk cid1.
lcb.push_gap(Some(cid0), cid1, Some(cid3), 'g');

Expand Down Expand Up @@ -361,6 +371,19 @@ mod tests {
});
}

#[test]
fn test_chunk_too_large() {
let mut lcb = LinkedChunkBuilder::<3, char, char>::new();

let cid0 = ChunkIdentifier::new(0);

// Adding a chunk with 4 items will fail, because the max capacity specified in
// the builder generics is 3.
let res = lcb.push_items(None, cid0, None, vec!['a', 'b', 'c', 'd']);

assert_matches!(res, Err(PushItemsChunkError::ChunkTooLarge));
}

#[test]
fn test_cycle() {
let mut lcb = LinkedChunkBuilder::<3, char, char>::new();
Expand All @@ -370,8 +393,8 @@ mod tests {
let cid2 = ChunkIdentifier::new(2);

lcb.push_gap(Some(cid2), cid0, Some(cid1), 'g');
lcb.push_items(Some(cid0), cid1, Some(cid2), ['a', 'b', 'c']);
lcb.push_items(Some(cid1), cid2, Some(cid0), ['d', 'e', 'f']);
lcb.push_items(Some(cid0), cid1, Some(cid2), ['a', 'b', 'c']).unwrap();
lcb.push_items(Some(cid1), cid2, Some(cid0), ['d', 'e', 'f']).unwrap();

let err = lcb.build().unwrap_err();
assert_matches!(err, LinkedChunkBuilderError::Cycle { path } => {
Expand All @@ -389,9 +412,9 @@ mod tests {

// cid0 and cid1 are linked to each other.
lcb.push_gap(None, cid0, Some(cid1), 'g');
lcb.push_items(Some(cid0), cid1, None, ['a', 'b', 'c']);
lcb.push_items(Some(cid0), cid1, None, ['a', 'b', 'c']).unwrap();
// cid2 stands on its own.
lcb.push_items(None, cid2, None, ['d', 'e', 'f']);
lcb.push_items(None, cid2, None, ['d', 'e', 'f']).unwrap();

let err = lcb.build().unwrap_err();
assert_matches!(err, LinkedChunkBuilderError::MultipleConnectedComponents { chunks } => {
Expand Down

0 comments on commit 1215b8b

Please sign in to comment.