Preserve exchange allocations during atomic replacement and reserve generated aliases
This commit is contained in:
@@ -203,6 +203,9 @@ pub fn remap_references(p: &mut Project, old: Id, new: Id) {
|
||||
}
|
||||
/// IDs removed by a cascade. Cross-layer traced counterparts are never included.
|
||||
pub fn deletion_impact(p: &Project, id: Id) -> BTreeSet<Id> {
|
||||
deletion_impact_inner(p, id, false)
|
||||
}
|
||||
fn deletion_impact_inner(p: &Project, id: Id, defer_exchange_allocations: bool) -> BTreeSet<Id> {
|
||||
let mut removed = BTreeSet::from([id]);
|
||||
loop {
|
||||
let before = removed.len();
|
||||
@@ -254,12 +257,15 @@ pub fn deletion_impact(p: &Project, id: Id) -> BTreeSet<Id> {
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if p.relations.values().any(|allocation| {
|
||||
allocation.kind() == RelationKind::PortAllocation
|
||||
&& removed.contains(&allocation.id)
|
||||
&& [boundary.source(), boundary.target()].contains(&allocation.source())
|
||||
&& [*source_port, *target_port].contains(&allocation.target())
|
||||
}) {
|
||||
if !defer_exchange_allocations
|
||||
&& p.relations.values().any(|allocation| {
|
||||
allocation.kind() == RelationKind::PortAllocation
|
||||
&& removed.contains(&allocation.id)
|
||||
&& [boundary.source(), boundary.target()].contains(&allocation.source())
|
||||
&& [*source_port, *target_port].contains(&allocation.target())
|
||||
})
|
||||
&& crate::ports::missing_exchange_port_allocations(p, r, &removed)
|
||||
{
|
||||
removed.insert(r.id);
|
||||
}
|
||||
}
|
||||
@@ -288,6 +294,40 @@ pub fn deletion_impact(p: &Project, id: Id) -> BTreeSet<Id> {
|
||||
}
|
||||
pub fn delete_cascade(p: &mut Project, id: Id) {
|
||||
let removed = deletion_impact(p, id);
|
||||
remove_objects(p, removed);
|
||||
}
|
||||
/// Preserve conditional exchange-allocation dependents until the transaction
|
||||
/// has had the opportunity to supply explicit replacement allocation facts.
|
||||
pub(crate) fn delete_cascade_deferred(p: &mut Project, id: Id, pending: &mut BTreeSet<Id>) {
|
||||
let complete = deletion_impact(p, id);
|
||||
let removed = deletion_impact_inner(p, id, true);
|
||||
// An explicitly removed relation cannot pass its conditional cascade on
|
||||
// to a new relation that later reuses the same identity in this batch.
|
||||
pending.retain(|id| !removed.contains(id));
|
||||
pending.extend(
|
||||
complete
|
||||
.difference(&removed)
|
||||
.filter(|id| {
|
||||
p.relations
|
||||
.get(id)
|
||||
.is_some_and(|r| r.kind() == RelationKind::ExchangeAllocation)
|
||||
})
|
||||
.copied(),
|
||||
);
|
||||
remove_objects(p, removed);
|
||||
}
|
||||
pub(crate) fn finish_deletions(p: &mut Project, pending: &BTreeSet<Id>) {
|
||||
let none = BTreeSet::new();
|
||||
for id in pending {
|
||||
if p.relations.get(id).is_some_and(|r| {
|
||||
r.kind() == RelationKind::ExchangeAllocation
|
||||
&& crate::ports::missing_exchange_port_allocations(p, r, &none)
|
||||
}) {
|
||||
delete_cascade(p, *id);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn remove_objects(p: &mut Project, removed: BTreeSet<Id>) {
|
||||
let removed_names: std::collections::BTreeMap<_, _> = removed
|
||||
.iter()
|
||||
.map(|id| (*id, p.named(*id).to_string()))
|
||||
|
||||
Reference in New Issue
Block a user