@@ -32,9 +32,61 @@ use super::{
32
32
type ChunkLength = usize ;
33
33
34
34
pin_project ! {
35
- /// A type used to transform a `Stream<Item = Vec<Update<Item, Gap>>>` into
36
- /// a `Stream<Item = Vec<VectorDiff<Item>>>`. Basically, it helps to consume
37
- // a [`LinkedChunk<CAP, Item, Gap>`] as if it was an [`ObservableVector<Item>`].
35
+ /// A type that transforms a `Stream<Item = Vec<Update<Item, Gap>>>` —given by
36
+ /// [`UpdateSubscriber`]— into a `Stream<Item = Vec<VectorDiff<Item>>>` —this
37
+ /// type—. Basically, it helps to consume a [`LinkedChunk<CAP, Item, Gap>`] as
38
+ /// if it was an [`eyeball::ObservableVector<Item>`].
39
+ ///
40
+ /// How this type transforms `Update` into `VectorDiff`? There is no internal
41
+ /// buffer of kind [`eyeball_im::ObservableVector<Item>`], which could have been
42
+ /// used to generate the `VectorDiff`s. They are computed manually.
43
+ ///
44
+ /// The only buffered data is pairs of [`ChunkIdentifier`] and [`ChunkLength`].
45
+ /// The following rules must be respected:
46
+ ///
47
+ /// * A chunk of kind [`ChunkContent::Gap`] has a length of 0,
48
+ /// * A chunk of kind [`ChunkContent::Items`] has a length equals to its number
49
+ /// of items,
50
+ /// * The pairs must be ordered exactly like the chunks in [`LinkedChunk`], i.e.
51
+ /// the first pair must represent the first chunk, the last pair must
52
+ /// represent the last chunk.
53
+ ///
54
+ /// The only thing this algorithm does is maintaining the pairs:
55
+ ///
56
+ /// * [`Update::NewItemsChunk`] and [`Update::NewGapChunk`] are inserting a new
57
+ /// pair with a chunk length of 0 at the appropriate index,
58
+ /// * [`Update::RemoveChunk`] is removing a pair,
59
+ /// * [`Update::PushItems`] is increasing the length of the appropriate pair by
60
+ /// the number of new items, and is potentially emitting [`VectorDiff`],
61
+ /// * [`Update::DetachLastItems`] is decreasing the length of the appropriate pair
62
+ /// by the number of items to be detached; no [`VectorDiff`] is emitted,
63
+ /// * [`Update::ReattachItems`] and [`Update::ReattachItemsDone`] are
64
+ /// respectively muting or unmuting the emission of [`VectorDiff`] by
65
+ /// [`Update::PushItems`].
66
+ ///
67
+ /// The only `VectorDiff` that are emitted are [`VectorDiff::Insert`] or
68
+ /// [`VectorDiff::Append`] because a [`LinkedChunk`] is append-only.
69
+ ///
70
+ /// `VectorDiff::Append` is an optimisation when numerous `VectorDiff::Insert`s
71
+ /// have to be emitted at the last position.
72
+ ///
73
+ /// `VectorDiff::Insert` need an index. To compute this index, the algorithm
74
+ /// will iterate over all pairs to accumulate each chunk length until it finds
75
+ /// the appropriate pair (given by [`Update::PushItems::position_hint`]). This
76
+ /// is _the offset_. To this offset, the algorithm adds the position's index of
77
+ /// the new items (still given by [`Update::PushItems::position_hint`]). This is
78
+ /// _the index_. This logic works for all cases as long as pairs are maintained
79
+ /// according to the rules hereinabove.
80
+ ///
81
+ /// That's a pretty memory compact and computation efficient way to map a
82
+ /// `Stream<Item = Vec<Update<Item, Gap>>>` into a `Stream<Item =
83
+ /// Vec<VectorDiff<Item>>>`. The larger the `LinkedChunk` capacity is, the fewer
84
+ /// pairs the algorithm will have to handle, e.g. for 1'000 items and a
85
+ /// `LinkedChunk` capacity of 128, it's only 8 pairs, be 256 bytes.
86
+ ///
87
+ /// [`LinkedChunk`]: super::LinkedChunk
88
+ /// [`ChunkContent::Gap`]: super::ChunkContent::Gap
89
+ /// [`ChunkContent::Content`]: super::ChunkContent::Content
38
90
pub struct AsVectorSubscriber <Item , Gap > {
39
91
// The inner `UpdatesSubscriber`.
40
92
#[ pin]
0 commit comments