Output graph content with semantic-merge resolution. This is the merge-aware counterpart of [`output_graph_content`]. For every SCC whose lead vertex appears in `resolved`, the merged bytes are written directly and the remaining vertices are silently skipped. All other SCCs are handled identically to `output_graph_content`. If `resolved` is empty this function behaves exactly like [`output_gra
(
changes: &C,
hash_fn: F,
graph: &AliveGraph,
order: &OrderResult,
buffer: &mut V,
resolved: &ResolvedConflicts,
)
| 500 | /// If `resolved` is empty this function behaves exactly like |
| 501 | /// [`output_graph_content`]. |
| 502 | pub fn output_graph_content_resolved<C, F, V>( |
| 503 | changes: &C, |
| 504 | hash_fn: F, |
| 505 | graph: &AliveGraph, |
| 506 | order: &OrderResult, |
| 507 | buffer: &mut V, |
| 508 | resolved: &ResolvedConflicts, |
| 509 | ) -> OutputResult<()> |
| 510 | where |
| 511 | C: ChangeStore, |
| 512 | F: Fn(NodeId) -> Option<Hash>, |
| 513 | V: VertexBuffer, |
| 514 | { |
| 515 | // Fast path: nothing was resolved and no unresolved forks. |
| 516 | if resolved.is_empty() && resolved.unresolved_forks().is_empty() { |
| 517 | return output_graph_content(changes, hash_fn, graph, order, buffer); |
| 518 | } |
| 519 | |
| 520 | // Track conflict IDs |
| 521 | let mut conflict_id: usize = 0; |
| 522 | |
| 523 | // Track zombie state |
| 524 | let mut in_zombie: Option<usize> = None; |
| 525 | |
| 526 | // Track which fork-conflict vertices have already been emitted. |
| 527 | let mut fork_emitted: std::collections::HashSet<VertexId> = std::collections::HashSet::new(); |
| 528 | |
| 529 | for scc in order.sccs.iter().rev() { |
| 530 | if scc.is_empty() { |
| 531 | continue; |
| 532 | } |
| 533 | |
| 534 | let is_cyclic = scc.len() > 1; |
| 535 | |
| 536 | // ── Resolved SCC: emit merged bytes, no conflict markers ────── |
| 537 | if is_cyclic { |
| 538 | if let Some(merged) = resolved.get_merged(scc[0]) { |
| 539 | if !merged.is_empty() { |
| 540 | let synthetic = GraphNode::new( |
| 541 | NodeId::ROOT, |
| 542 | ChangePosition::new(0), |
| 543 | ChangePosition::new(merged.len() as u64), |
| 544 | ); |
| 545 | // Clone into a local so the closure can own it |
| 546 | // (`output_line` takes `FnOnce`). |
| 547 | let bytes = merged.to_vec(); |
| 548 | buffer |
| 549 | .output_line(synthetic, |buf: &mut [u8]| -> Result<(), std::io::Error> { |
| 550 | buf.copy_from_slice(&bytes); |
| 551 | Ok(()) |
| 552 | }) |
| 553 | .map_err(OutputError::io)?; |
| 554 | } |
| 555 | continue; // skip remaining vertices in this SCC |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | // ── Fork-resolved: single-vertex SCC with merged or skipped content ─ |