Find a block that ends at or after the given position. This is used for predecessors resolution where we need to find the span that ENDS at a position, not one that contains it. This is important when creating edges from an existing span to a new one. # Arguments `pos` - The position to find (typically the end of a context span) # Returns The span that ends at or after the given position, or
(&self, pos: Position<NodeId>)
| 147 | /// - Empty vertices (start == end == pos) are matched exactly |
| 148 | /// - For non-empty vertices, finds one where start < pos <= end |
| 149 | fn find_block_end(&self, pos: Position<NodeId>) -> PristineResult<GraphNode<NodeId>> { |
| 150 | // Handle ROOT position specially |
| 151 | if pos.change.is_root() { |
| 152 | return Ok(GraphNode::ROOT); |
| 153 | } |
| 154 | |
| 155 | let table = self.txn.open_multimap_table(GRAPH)?; |
| 156 | |
| 157 | let change_id = pos.change.get(); |
| 158 | let target_pos = pos.pos.get(); |
| 159 | |
| 160 | // FIRST: Check for empty span at exact position using direct lookup. |
| 161 | // This is important because empty vertices like inode markers (e.g., V[9:9]) |
| 162 | // must be found when predecessors references position 9, even if there's |
| 163 | // another span like V[0:9] that also ends at position 9. |
| 164 | // Without this direct lookup, iteration would return V[0:9] first since |
| 165 | // it has a lower start position. |
| 166 | let empty_key = encode_vertex(change_id, target_pos, target_pos); |
| 167 | if table.get(&empty_key)?.next().is_some() { |
| 168 | return Ok(GraphNode { |
| 169 | change: NodeId::new(change_id), |
| 170 | start: ChangePosition::new(target_pos), |
| 171 | end: ChangePosition::new(target_pos), |
| 172 | }); |
| 173 | } |
| 174 | |
| 175 | // SECOND: Fall back to iteration to find vertices that end at this position |
| 176 | let start_key = encode_vertex(change_id, 0, 0); |
| 177 | let end_key = encode_vertex(change_id, u64::MAX, u64::MAX); |
| 178 | |
| 179 | // Look for a span that ends at this position |
| 180 | for result in table.range::<&[u8; 24]>(&start_key..=&end_key)? { |
| 181 | let (key, _values) = result?; |
| 182 | let (v_change, v_start, v_end) = decode_vertex(key.value()); |
| 183 | |
| 184 | if v_change != change_id { |
| 185 | continue; |
| 186 | } |
| 187 | |
| 188 | // Check for span that ends at this position |
| 189 | // For predecessors, we want the span where end == target_pos |
| 190 | if v_end == target_pos && v_start < v_end { |
| 191 | return Ok(GraphNode { |
| 192 | change: NodeId::new(v_change), |
| 193 | start: ChangePosition::new(v_start), |
| 194 | end: ChangePosition::new(v_end), |
| 195 | }); |
| 196 | } |
| 197 | |
| 198 | // Also check if position falls within [start, end] |
| 199 | // This handles the case where we're looking for a span containing this position |
| 200 | if v_start <= target_pos && target_pos < v_end { |
| 201 | return Ok(GraphNode { |
| 202 | change: NodeId::new(v_change), |
| 203 | start: ChangePosition::new(v_start), |
| 204 | end: ChangePosition::new(v_end), |
| 205 | }); |
| 206 | } |
nothing calls this directly
no test coverage detected