(&self, pos: Position<NodeId>)
| 178 | } |
| 179 | |
| 180 | fn find_block_end(&self, pos: Position<NodeId>) -> PristineResult<GraphNode<NodeId>> { |
| 181 | // Handle ROOT position specially |
| 182 | if pos.change.is_root() { |
| 183 | return Ok(GraphNode::ROOT); |
| 184 | } |
| 185 | |
| 186 | let table = self.txn.open_multimap_table(GRAPH)?; |
| 187 | |
| 188 | let change_id = pos.change.get(); |
| 189 | let target_pos = pos.pos.get(); |
| 190 | |
| 191 | // FIRST: Check for empty span at exact position using direct lookup. |
| 192 | // This is important because empty vertices like inode markers (e.g., V[9:9]) |
| 193 | // must be found when predecessors references position 9, even if there's |
| 194 | // another span like V[0:9] that also ends at position 9. |
| 195 | // Without this direct lookup, iteration would return V[0:9] first since |
| 196 | // it has a lower start position. |
| 197 | let empty_key = encode_vertex(change_id, target_pos, target_pos); |
| 198 | if table.get(&empty_key)?.next().is_some() { |
| 199 | return Ok(GraphNode { |
| 200 | change: NodeId::new(change_id), |
| 201 | start: ChangePosition::new(target_pos), |
| 202 | end: ChangePosition::new(target_pos), |
| 203 | }); |
| 204 | } |
| 205 | |
| 206 | // SECOND: Fall back to iteration to find vertices that end at this position |
| 207 | let start_key = encode_vertex(change_id, 0, 0); |
| 208 | let end_key = encode_vertex(change_id, u64::MAX, u64::MAX); |
| 209 | |
| 210 | // Look for a span that ends at this position or contains it |
| 211 | for result in table.range::<&[u8; 24]>(&start_key..=&end_key)? { |
| 212 | let (key, _values) = result?; |
| 213 | let (v_change, v_start, v_end) = decode_vertex(key.value()); |
| 214 | |
| 215 | if v_change != change_id { |
| 216 | continue; |
| 217 | } |
| 218 | |
| 219 | // Check for span that ends at this position |
| 220 | if v_end == target_pos && v_start < v_end { |
| 221 | return Ok(GraphNode { |
| 222 | change: NodeId::new(v_change), |
| 223 | start: ChangePosition::new(v_start), |
| 224 | end: ChangePosition::new(v_end), |
| 225 | }); |
| 226 | } |
| 227 | |
| 228 | // Also check if position falls within [start, end) |
| 229 | if v_start <= target_pos && target_pos < v_end { |
| 230 | return Ok(GraphNode { |
| 231 | change: NodeId::new(v_change), |
| 232 | start: ChangePosition::new(v_start), |
| 233 | end: ChangePosition::new(v_end), |
| 234 | }); |
| 235 | } |
| 236 | } |
| 237 |
nothing calls this directly
no test coverage detected