Skip to content

Commit

Permalink
Merge pull request #2032 from hannobraun/replace
Browse files Browse the repository at this point in the history
Add `UpdateCycle::replace_edge`
  • Loading branch information
hannobraun authored Sep 27, 2023
2 parents b4999e6 + 03be493 commit 8267c76
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 11 deletions.
51 changes: 40 additions & 11 deletions crates/fj-core/src/objects/handles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,52 @@ impl<T> Handles<T> {
where
T: Debug + Ord,
{
let mut updated = Some(update(handle));
self.replace(handle, |handle| [update(handle)])
}

/// Create a new instance in which the provided item has been replaced
///
/// This is a more general version of [`Handles::update`] which can replace
/// a single item with multiple others.
///
/// # Panics
///
/// Panics, if the provided item is not present.
/// Panics, if the update results in a duplicate item.
#[must_use]
pub fn replace<const N: usize>(
&self,
handle: &Handle<T>,
replace: impl FnOnce(&Handle<T>) -> [Handle<T>; N],
) -> Self
where
T: Debug + Ord,
{
let mut iter = self.iter().cloned().peekable();

// Collect all items before the item we want to update.
let mut before = Vec::new();
loop {
let h = match iter.peek() {
Some(h) => h,
None => panic!("Item not found"),
};

let items = self.iter().map(|h| {
if h.id() == handle.id() {
updated
.take()
.expect("`Handles` should not contain same item twice")
} else {
h.clone()
// Found the item we want to update. Remove it from the
// iterator, then move on.
iter.next();
break;
}
});

let handles = items.collect();
let next = iter.next().expect("Peek just returned `Some`");
before.push(next.clone());
}

assert!(updated.is_none(), "Edge not found in cycle");
let replaced = replace(handle);
let after = iter;

handles
before.into_iter().chain(replaced).chain(after).collect()
}
}

Expand Down
26 changes: 26 additions & 0 deletions crates/fj-core/src/operations/update/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ pub trait UpdateCycle {
edge: &Handle<Edge>,
update: impl FnOnce(&Handle<Edge>) -> Handle<Edge>,
) -> Self;

/// Replace the provided edge
///
/// This is a more general version of [`UpdateCycle::update_edge`] which can
/// replace a single edge with multiple others.
///
/// # Panics
///
/// Uses [`Handles::update`] internally, and panics for the same reasons.
///
/// [`Handles::update`]: crate::objects::Handles::update
#[must_use]
fn replace_edge<const N: usize>(
&self,
edge: &Handle<Edge>,
replace: impl FnOnce(&Handle<Edge>) -> [Handle<Edge>; N],
) -> Self;
}

impl UpdateCycle for Cycle {
Expand All @@ -38,4 +55,13 @@ impl UpdateCycle for Cycle {
let edges = self.edges().update(edge, update);
Cycle::new(edges)
}

fn replace_edge<const N: usize>(
&self,
edge: &Handle<Edge>,
replace: impl FnOnce(&Handle<Edge>) -> [Handle<Edge>; N],
) -> Self {
let edges = self.edges().replace(edge, replace);
Cycle::new(edges)
}
}

0 comments on commit 8267c76

Please sign in to comment.