Skip to content

Commit f5144d7

Browse files
📝 Add docstrings to cli/serial-creation
* 📝 Add docstrings to `cli/serial-creation` Docstrings generation was requested by @ChanTsune. * #2635 (comment) The following files were modified: * `cli/src/command/core.rs` * `cli/src/command/core/iter.rs` * `cli/src/command/create.rs` * `cli/src/command/update.rs` * `cli/tests/cli/append/entry_order.rs` * `cli/tests/cli/create/entry_order.rs` * `cli/tests/cli/update/entry_order.rs` * ♻️ Keep only iter.rs docstrings and add unit tests - Revert docstring changes to core.rs, create.rs, update.rs, and test files - Keep OrderedByIndex documentation in iter.rs - Replace doc examples with actual unit tests in mod tests --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: ChanTsune <41658782+ChanTsune@users.noreply.github.com>
1 parent 74c2c36 commit f5144d7

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

cli/src/command/core/iter.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ use std::collections::HashMap;
22

33
/// Reorders `(usize, T)` items into index order, buffering out-of-order items.
44
///
5+
/// Used to preserve original argument order when parallel processing may
6+
/// produce results in arbitrary order.
7+
///
8+
/// # Preconditions
9+
///
510
/// This iterator expects indices to be contiguous starting at `start`.
11+
/// If any index in the expected sequence is missing from the input,
12+
/// subsequent items will be buffered but never yielded (silently dropped).
13+
///
14+
/// Each index should appear at most once. If duplicate indices are provided,
15+
/// only the last item with that index will be retained (earlier items are
16+
/// silently overwritten).
617
#[derive(Debug)]
718
pub(crate) struct OrderedByIndex<I, T>
819
where
@@ -17,10 +28,23 @@ impl<I, T> OrderedByIndex<I, T>
1728
where
1829
I: Iterator<Item = (usize, T)>,
1930
{
31+
/// Creates an `OrderedByIndex` that yields items in ascending index order starting from 0.
32+
///
33+
/// `iter` is the underlying iterator that yields `(index, item)` pairs;
34+
/// out-of-order items are buffered until their index becomes the next expected value.
2035
pub(crate) fn new(iter: I) -> Self {
2136
Self::with_start(iter, 0)
2237
}
2338

39+
/// Creates an `OrderedByIndex` iterator that yields items starting from `start`
40+
/// and buffers out-of-order items until their index becomes the next expected.
41+
///
42+
/// `iter` must produce `(usize, T)` pairs where the `usize` is the item's
43+
/// original index. The resulting iterator emits `T` values in ascending index
44+
/// order beginning at `start`.
45+
///
46+
/// See the struct-level documentation for preconditions regarding index
47+
/// contiguity and uniqueness.
2448
pub(crate) fn with_start(iter: I, start: usize) -> Self {
2549
Self {
2650
iter,
@@ -36,6 +60,12 @@ where
3660
{
3761
type Item = T;
3862

63+
/// Advances the ordered iterator and yields the next item whose index matches
64+
/// the current expected index.
65+
///
66+
/// Returns the next buffered or incoming item with the smallest contiguous index
67+
/// equal to the iterator's current expectation; when the underlying iterator is
68+
/// exhausted and no matching buffered item exists, iteration ends.
3969
fn next(&mut self) -> Option<Self::Item> {
4070
loop {
4171
if let Some(item) = self.buffer.remove(&self.next) {
@@ -56,3 +86,45 @@ where
5686
}
5787
}
5888
}
89+
90+
#[cfg(test)]
91+
mod tests {
92+
use super::*;
93+
94+
#[test]
95+
fn reorders_out_of_order_items() {
96+
let iter = vec![(1, 20), (0, 10)].into_iter();
97+
let mut ordered = OrderedByIndex::new(iter);
98+
assert_eq!(ordered.next(), Some(10));
99+
assert_eq!(ordered.next(), Some(20));
100+
assert_eq!(ordered.next(), None);
101+
}
102+
103+
#[test]
104+
fn with_start_reorders_from_given_index() {
105+
let src = vec![(2, "a"), (4, "c"), (3, "b")];
106+
let out: Vec<_> = OrderedByIndex::with_start(src.into_iter(), 2).collect();
107+
assert_eq!(out, vec!["a", "b", "c"]);
108+
}
109+
110+
#[test]
111+
fn handles_already_ordered_items() {
112+
let items = vec![(0, 'a'), (1, 'b'), (2, 'c')];
113+
let out: Vec<_> = OrderedByIndex::new(items.into_iter()).collect();
114+
assert_eq!(out, vec!['a', 'b', 'c']);
115+
}
116+
117+
#[test]
118+
fn handles_reverse_order() {
119+
let items = vec![(2, 'c'), (1, 'b'), (0, 'a')];
120+
let out: Vec<_> = OrderedByIndex::new(items.into_iter()).collect();
121+
assert_eq!(out, vec!['a', 'b', 'c']);
122+
}
123+
124+
#[test]
125+
fn handles_empty_iterator() {
126+
let items: Vec<(usize, i32)> = vec![];
127+
let out: Vec<_> = OrderedByIndex::new(items.into_iter()).collect();
128+
assert!(out.is_empty());
129+
}
130+
}

cli/src/command/update.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ where
560560
});
561561
Ok(None)
562562
} else {
563+
// NOTE: Entry doesn't need update - write it directly to archive.
564+
// We still send a placeholder to the channel to maintain index
565+
// continuity for OrderedByIndex, preventing it from blocking
566+
// on this index forever.
563567
tx.send((idx, Ok(None)))
564568
.unwrap_or_else(|e| log::error!("{e}: {}", entry.header().path()));
565569
Ok(Some(entry))
@@ -636,6 +640,10 @@ where
636640
});
637641
Ok(None)
638642
} else {
643+
// NOTE: Entry doesn't need update - write it directly to archive.
644+
// We still send a placeholder to the channel to maintain index
645+
// continuity for OrderedByIndex, preventing it from blocking
646+
// on this index forever.
639647
tx.send((idx, Ok(None)))
640648
.unwrap_or_else(|e| log::error!("{e}: {}", entry.header().path()));
641649
Ok(Some(entry))

0 commit comments

Comments
 (0)