Skip to content

Commit b3f3dde

Browse files
committed
Implement DoubleEndedIterator for fn children
1 parent 65d257c commit b3f3dde

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed

hugr-persistent/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ name = "persistent_walker_example"
1818
[dependencies]
1919
hugr-core = { path = "../hugr-core", version = "0.23.0" }
2020

21-
derive_more = { workspace = true, features = ["display", "error", "from"] }
21+
derive_more = { workspace = true, features = [
22+
"display",
23+
"error",
24+
"from",
25+
"debug",
26+
] }
2227
delegate.workspace = true
2328
itertools.workspace = true
2429
petgraph.workspace = true

hugr-persistent/src/trait_impls.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ use super::{
2525
InvalidCommit, PatchNode, PersistentHugr, PersistentReplacement, state_space::CommitData,
2626
};
2727

28+
mod utils;
29+
use utils::DoubleEndedIteratorAdapter;
30+
2831
impl Patch<PersistentHugr> for PersistentReplacement {
2932
type Outcome = CommitId;
3033
const UNCHANGED_ON_FAILURE: bool = true;
@@ -226,14 +229,15 @@ impl HugrView for PersistentHugr {
226229
let cm = self.get_commit(node.owner());
227230
let commit_hugr = cm.commit_hugr();
228231
let children = commit_hugr.children(node.1).map(|n| cm.to_patch_node(n));
229-
if OpTag::DataflowParent.is_superset(self.get_optype(node).tag()) {
232+
let it = if OpTag::DataflowParent.is_superset(self.get_optype(node).tag()) {
230233
// we must filter out children nodes that are invalidated by later commits, and
231234
// on the other hand add nodes in those commits
232235
Either::Left(IterValidNodes::new(self, children.fuse()))
233236
} else {
234237
// children are precisely children of the commit hugr
235238
Either::Right(children)
236-
}
239+
};
240+
DoubleEndedIteratorAdapter::from(it)
237241
}
238242

239243
fn descendants(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> + Clone {
@@ -407,11 +411,7 @@ impl<I: FusedIterator<Item = PatchNode>> Iterator for IterValidNodes<'_, I> {
407411
}
408412
}
409413

410-
impl<I: FusedIterator<Item = PatchNode>> DoubleEndedIterator for IterValidNodes<'_, I> {
411-
fn next_back(&mut self) -> Option<Self::Item> {
412-
unimplemented!("cannot go backwards")
413-
}
414-
}
414+
impl<I: FusedIterator<Item = PatchNode>> FusedIterator for IterValidNodes<'_, I> {}
415415

416416
#[cfg(test)]
417417
mod tests {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::iter::FusedIterator;
2+
3+
/// An adapter that allows an `Iterator` to implement `DoubleEndedIterator`
4+
/// by collecting its items when `next_back` is called.
5+
///
6+
/// If `next_back` is never called, the original iterator is used directly,
7+
/// avoiding the overhead of collecting items into a vector.
8+
#[derive(Clone, Debug)]
9+
pub enum DoubleEndedIteratorAdapter<I: Iterator> {
10+
Iter(I),
11+
CollectedIter(std::vec::IntoIter<I::Item>),
12+
}
13+
14+
impl<I: Iterator> DoubleEndedIteratorAdapter<I> {
15+
/// Creates a new `DoubleEndedIteratorAdapter` from the given iterator.
16+
pub fn new(iter: I) -> Self {
17+
Self::Iter(iter)
18+
}
19+
20+
fn collect_self(&mut self) {
21+
match self {
22+
DoubleEndedIteratorAdapter::Iter(iter) => {
23+
let collected: Vec<I::Item> = iter.collect();
24+
*self = DoubleEndedIteratorAdapter::CollectedIter(collected.into_iter());
25+
}
26+
DoubleEndedIteratorAdapter::CollectedIter(_) => {}
27+
}
28+
}
29+
}
30+
31+
impl<I: Iterator> From<I> for DoubleEndedIteratorAdapter<I> {
32+
fn from(iter: I) -> Self {
33+
Self::new(iter)
34+
}
35+
}
36+
37+
impl<I: Iterator> Iterator for DoubleEndedIteratorAdapter<I> {
38+
type Item = I::Item;
39+
40+
fn next(&mut self) -> Option<Self::Item> {
41+
match self {
42+
DoubleEndedIteratorAdapter::Iter(iter) => iter.next(),
43+
DoubleEndedIteratorAdapter::CollectedIter(iter) => iter.next(),
44+
}
45+
}
46+
47+
fn size_hint(&self) -> (usize, Option<usize>) {
48+
match self {
49+
DoubleEndedIteratorAdapter::Iter(iter) => iter.size_hint(),
50+
DoubleEndedIteratorAdapter::CollectedIter(iter) => iter.size_hint(),
51+
}
52+
}
53+
}
54+
55+
impl<I: FusedIterator> FusedIterator for DoubleEndedIteratorAdapter<I> {}
56+
57+
impl<I: Iterator> DoubleEndedIterator for DoubleEndedIteratorAdapter<I> {
58+
fn next_back(&mut self) -> Option<Self::Item> {
59+
self.collect_self();
60+
match self {
61+
DoubleEndedIteratorAdapter::CollectedIter(iter) => iter.next_back(),
62+
_ => unreachable!("just collected self"),
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)