use super::*;
/// Find the key where a position is.
pub(crate) fn find_block<'db, 'txn: 'db, T: TxnT>(
txn: &'txn T,
channel: &'db Channel<T>,
p: Position<ChangeId>,
) -> Result<Vertex<ChangeId>, crate::Error> {
if p.change.is_root() {
return Ok(Vertex::ROOT);
}
let key = Vertex {
change: p.change,
start: p.pos,
end: p.pos,
};
debug!(target: "libpijul::find_block", "find_block {:?}", key);
let mut cursor = txn.cursor_graph(&channel.graph, Some((key, None)));
let mut k = if let Some((k, _)) = cursor.next() {
k
} else {
return Err(crate::Error::WrongBlock { block: p });
};
debug!("k = {:?}", k);
// The only guarantee here is that k is either the first key
// >= `key`, or the key just before that. We might need to
// rewind by one step if key is strictly larger than the
// result (i.e. if `p` is in the middle of the key).
while k.change > p.change || (k.change == p.change && k.start > p.pos) {
debug!(target: "libpijul::find_block", "find_block while {:?}", k);
if let Some((k_, _)) = cursor.prev() {
k = k_
} else {
break;
}
}
loop {
debug!(target: "libpijul::find_block", "find_block loop {:?}", k);
if k.change == p.change && k.start <= p.pos {
if k.end > p.pos || (k.start == k.end && k.end == p.pos) {
return Ok(k);
}
} else if k.change > p.change {
return Err(crate::Error::WrongBlock { block: p });
}
if let Some((k_, _)) = cursor.next() {
k = k_
} else {
break;
}
}
debug!(target: "libpijul::find_block", "find_block None, {:?}", k);
Err(crate::Error::WrongBlock { block: p })
}
/// Find the key ending at a position.
pub(crate) fn find_block_end<'db, 'txn: 'db, T: TxnT>(
txn: &'txn T,
channel: &'db Channel<T>,
p: Position<ChangeId>,
) -> Result<Vertex<ChangeId>, crate::Error> {
if p.change.is_root() {
return Ok(Vertex::ROOT);
}
let key = Vertex {
change: p.change,
start: p.pos,
end: p.pos,
};
debug!(target: "libpijul::find_block_end", "find_block_end {:?}, p.change.0 = {:?}", key, p.change.0);
let mut cursor = txn.cursor_graph(&channel.graph, Some((key, None)));
let mut k = if let Some((k, _)) = cursor.next() {
k
} else {
return Err(crate::Error::WrongBlock { block: p });
};
// The only guarantee here is that k is either the first key
// before `key`, or the key just before that.
loop {
debug!(target: "libpijul::find_block_end", "find_block_end loop {:?} k.change.0 = {:?}", k, k.change.0);
if k.change < p.change {
break;
} else if k.change == p.change {
// Here we want to create an edge pointing between `p`
// and its successor. If k.start == p.pos, the only
// case where that's what we want is if k.start ==
// k.end.
if k.start == p.pos && k.end == p.pos {
break;
} else if k.start < p.pos {
break;
}
}
if let Some((k_, _)) = cursor.prev() {
k = k_
} else {
break;
}
}
// We also want k.end >= p.pos, so we just call next() until
// we have that.
debug!(target: "libpijul::find_block_end", "find_block_end k(0) = {:?} k.change.0 = {:?}", k, k.change.0);
while k.change < p.change || (k.change == p.change && p.pos > k.end) {
if let Some((k_, _)) = cursor.next() {
k = k_
} else {
break;
}
}
debug!(target: "libpijul::find_block_end", "find_block_end k(1) = {:?}, k.change.0 = {:?}", k, k.change.0);
if k.change == p.change && k.start <= p.pos && p.pos <= k.end {
Ok(k)
} else {
Err(crate::Error::WrongBlock { block: p })
}
}