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

Function canonicalize_session_turns

atomic-core/src/change/session.rs:81–143  ·  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

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

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