use super::change_id::*;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct Vertex<H> {
pub change: H,
pub start: ChangePosition,
pub end: ChangePosition,
}
impl Vertex<ChangeId> {
pub const ROOT: Vertex<ChangeId> = Vertex {
change: ChangeId::ROOT,
start: ChangePosition::ROOT,
end: ChangePosition::ROOT,
};
pub(crate) const BOTTOM: Vertex<ChangeId> = Vertex {
change: ChangeId::ROOT,
start: ChangePosition::BOTTOM,
end: ChangePosition::BOTTOM,
};
pub fn is_root(&self) -> bool {
self == &Vertex::ROOT
}
pub(crate) fn to_option(&self) -> Vertex<Option<ChangeId>> {
Vertex {
change: Some(self.change),
start: self.start,
end: self.end,
}
}
}
impl<H: Clone> Vertex<H> {
pub fn start_pos(&self) -> Position<H> {
Position {
change: self.change.clone(),
pos: self.start,
}
}
pub fn end_pos(&self) -> Position<H> {
Position {
change: self.change.clone(),
pos: self.end,
}
}
pub fn is_empty(&self) -> bool {
self.end == self.start
}
pub fn len(&self) -> usize {
self.end - self.start
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct ChangePosition(pub u64);
impl ChangePosition {
pub(crate) const ROOT: ChangePosition = ChangePosition(0);
pub(crate) const BOTTOM: ChangePosition = ChangePosition(1);
}
impl std::ops::Add<usize> for ChangePosition {
type Output = ChangePosition;
fn add(self, x: usize) -> Self::Output {
ChangePosition(self.0 + x as u64)
}
}
impl std::ops::Sub<ChangePosition> for ChangePosition {
type Output = usize;
fn sub(self, x: ChangePosition) -> Self::Output {
(self.0 - x.0) as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
#[doc(hidden)]
pub struct Position<P> {
pub change: P,
pub pos: ChangePosition,
}
use super::Base32;
use byteorder::{ByteOrder, LittleEndian};
impl<H: super::Base32> Base32 for Position<H> {
fn to_base32(&self) -> String {
let mut v = self.change.to_base32();
let mut bytes = [0; 8];
LittleEndian::write_u64(&mut bytes, self.pos.0);
let mut i = 7;
while i > 2 && bytes[i] == 0 {
i -= 1
}
i += 1;
let len = data_encoding::BASE32_NOPAD.encode_len(i);
let len0 = v.len() + 1;
v.push_str("..............");
v.truncate(len0 + len);
data_encoding::BASE32_NOPAD.encode_mut(&bytes[..i], unsafe {
v.split_at_mut(len0).1.as_bytes_mut()
});
v
}
fn from_base32(s: &[u8]) -> Option<Self> {
let n = s.iter().position(|c| *c == b'.')?;
let (s, pos) = s.split_at(n);
let pos = &pos[1..];
let change = H::from_base32(s)?;
let mut dec = [0; 8];
let len = data_encoding::BASE32_NOPAD.decode_len(pos.len()).ok()?;
let pos = data_encoding::BASE32_NOPAD
.decode_mut(pos, &mut dec[..len])
.map(|_| LittleEndian::read_u64(&dec))
.ok()?;
Some(Position {
change,
pos: ChangePosition(pos),
})
}
}
impl<H> std::ops::Add<usize> for Position<H> {
type Output = Position<H>;
fn add(self, x: usize) -> Self::Output {
Position {
change: self.change,
pos: self.pos + x,
}
}
}
impl Position<ChangeId> {
pub fn inode_vertex(&self) -> Vertex<ChangeId> {
Vertex {
change: self.change,
start: self.pos,
end: self.pos,
}
}
pub fn is_root(&self) -> bool {
self.change.is_root()
}
pub(crate) fn to_option(&self) -> Position<Option<ChangeId>> {
Position {
change: Some(self.change),
pos: self.pos,
}
}
pub const ROOT: Position<ChangeId> = Position {
change: ChangeId::ROOT,
pos: ChangePosition(0),
};
pub(crate) const OPTION_ROOT: Position<Option<ChangeId>> = Position {
change: Some(ChangeId::ROOT),
pos: ChangePosition(0),
};
pub(crate) const BOTTOM: Position<ChangeId> = Position {
change: ChangeId::ROOT,
pos: ChangePosition::BOTTOM,
};
}