MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / canonicalize_session_turns

Function canonicalize_session_turns

atomic-core/src/change/session.rs:74–136  ·  view source on GitHub ↗

Return a deterministic, causality-aware ordering for a session's turns. Stored provenance can arrive in any order (for example during pull). A timestamp plus full provenance hash provides a stable tie-break, while the `previous_provenance` link keeps a child after its parent when both are present. Turn numbers are reassigned from zero after ordering.

(turns: Vec<SessionTurn>)

Source from the content-addressed store, hash-verified

72/// `previous_provenance` link keeps a child after its parent when both are
73/// present. Turn numbers are reassigned from zero after ordering.
74pub fn canonicalize_session_turns(turns: Vec<SessionTurn>) -> Vec<SessionTurn> {
75 type SortKey = (i64, [u8; 32], usize);
76
77 let count = turns.len();
78 let positions: std::collections::HashMap<Hash, usize> = turns
79 .iter()
80 .enumerate()
81 .map(|(index, turn)| (turn.provenance_hash, index))
82 .collect();
83 let sort_keys: Vec<SortKey> = turns
84 .iter()
85 .enumerate()
86 .map(|(index, turn)| (turn.timestamp, *turn.provenance_hash.as_bytes(), index))
87 .collect();
88 let mut children = vec![Vec::new(); count];
89 let mut blocked = vec![false; count];
90
91 for (index, turn) in turns.iter().enumerate() {
92 if let Some(parent) = turn
93 .previous_provenance
94 .and_then(|hash| positions.get(&hash).copied())
95 {
96 blocked[index] = true;
97 children[parent].push(index);
98 }
99 }
100
101 let mut remaining: std::collections::BTreeSet<SortKey> = sort_keys.iter().copied().collect();
102 let mut ready: std::collections::BTreeSet<SortKey> = sort_keys
103 .iter()
104 .copied()
105 .filter(|key| !blocked[key.2])
106 .collect();
107 let mut slots: Vec<Option<SessionTurn>> = turns.into_iter().map(Some).collect();
108 let mut ordered = Vec::with_capacity(count);
109
110 while ordered.len() < count {
111 // If malformed provenance contains a cycle, break it at the same
112 // timestamp/hash point in every repository.
113 let key = ready
114 .pop_first()
115 .or_else(|| remaining.first().copied())
116 .expect("remaining turn while canonicalizing");
117 remaining.remove(&key);
118 let index = key.2;
119 let Some(turn) = slots[index].take() else {
120 continue;
121 };
122 ordered.push(turn);
123
124 for child in &children[index] {
125 if blocked[*child] {
126 blocked[*child] = false;
127 ready.insert(sort_keys[*child]);
128 }
129 }
130 }
131

Calls 9

iter_mutMethod · 0.80
getMethod · 0.65
removeMethod · 0.65
lenMethod · 0.45
iterMethod · 0.45
as_bytesMethod · 0.45
pushMethod · 0.45
into_iterMethod · 0.45
insertMethod · 0.45