use super::patch_id::*;
use bs58;
use sanakirja::{Alignment, Representable};
use std;
use Hash;
const LINE_ID_SIZE: usize = 8;
pub const KEY_SIZE: usize = PATCH_ID_SIZE + LINE_ID_SIZE;
pub const ROOT_KEY: Key<PatchId> = Key {
patch: ROOT_PATCH_ID,
line: LineId(0),
};
use hex::ToHex;
use std::fmt::Write;
impl ToHex for Key<PatchId> {
fn write_hex<W: Write>(&self, w: &mut W) -> std::fmt::Result {
self.patch.write_hex(w)?;
self.line.write_hex(w)
}
fn write_hex_upper<W: Write>(&self, w: &mut W) -> std::fmt::Result {
self.patch.write_hex(w)?;
self.line.write_hex(w)
}
}
impl Key<PatchId> {
pub fn to_base58(&self) -> String {
let mut b = self.patch.to_base58();
let mut x = [0; 8];
LittleEndian::write_u64(&mut x, self.line.0);
bs58::encode(&x).into(&mut b);
b
}
pub fn to_hex(&self) -> String {
let mut s = String::new();
self.write_hex(&mut s).unwrap();
s
}
}
impl Key<Hash> {
pub fn to_base58(&self) -> String {
let mut b = self.patch.to_base58();
let mut x = [0; 8];
LittleEndian::write_u64(&mut x, self.line.0);
bs58::encode(&x).into(&mut b);
b
}
}
impl Key<PatchId> {
pub fn is_root(&self) -> bool {
self == &ROOT_KEY
}
pub fn from_hex(hex: &str) -> Option<Self> {
let mut s = [0; KEY_SIZE];
if super::from_hex(hex, &mut s) {
Some(Key {
patch: PatchId(LittleEndian::read_u64(&s[..8])),
line: LineId(LittleEndian::read_u64(&s[8..])),
})
} else {
None
}
}
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct LineId(pub u64);
impl ToHex for LineId {
fn write_hex<W: Write>(&self, w: &mut W) -> std::fmt::Result {
PatchId(self.0).write_hex(w)
}
fn write_hex_upper<W: Write>(&self, w: &mut W) -> std::fmt::Result {
PatchId(self.0).write_hex_upper(w)
}
}
impl std::fmt::Debug for LineId {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "LineId(0x{})", self.to_hex())
}
}
impl LineId {
pub fn new() -> LineId {
LineId(0)
}
pub fn is_root(&self) -> bool {
self.0 == 0
}
pub fn to_hex(&self) -> String {
let mut s = String::new();
self.write_hex(&mut s).unwrap();
s
}
pub fn to_base58(&self) -> String {
let mut x = [0; 8];
LittleEndian::write_u64(&mut x, self.0);
let mut b = String::new();
bs58::encode(&x).into(&mut b);
b
}
pub fn from_base58(s: &str) -> Option<Self> {
let mut p = [0; 8];
if bs58::decode(s).into(&mut p).is_ok() {
Some(LineId(LittleEndian::read_u64(&p)))
} else {
None
}
}
}
use byteorder::{ByteOrder, LittleEndian};
impl std::ops::Add<usize> for LineId {
type Output = LineId;
fn add(self, x: usize) -> Self::Output {
LineId(self.0 + x as u64)
}
}
impl std::ops::AddAssign<usize> for LineId {
fn add_assign(&mut self, x: usize) {
*self = self.clone() + x
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct Key<H> {
pub patch: H,
pub line: LineId,
}
#[test]
fn test_key_alignment() {
assert_eq!(std::mem::size_of::<Key<PatchId>>(), 16)
}
impl<T> AsRef<LineId> for Key<T> {
fn as_ref(&self) -> &LineId {
&self.line
}
}
impl<T: Clone> Key<Option<T>> {
pub fn unwrap_patch(&self) -> Key<T> {
Key {
patch: self.patch.as_ref().unwrap().clone(),
line: self.line.clone(),
}
}
}
impl Representable for Key<PatchId> {
fn alignment() -> Alignment {
Alignment::B1
}
fn onpage_size(&self) -> u16 {
(PATCH_ID_SIZE + LINE_ID_SIZE) as u16
}
unsafe fn write_value(&self, p: *mut u8) {
trace!("write_value {:?}", p);
let p = std::slice::from_raw_parts_mut(p, KEY_SIZE);
LittleEndian::write_u64(p, self.patch.0);
LittleEndian::write_u64(&mut p[PATCH_ID_SIZE..], self.line.0);
}
unsafe fn read_value(p: *const u8) -> Self {
trace!("read_value {:?}", p);
let p = std::slice::from_raw_parts(p, KEY_SIZE);
let patch = LittleEndian::read_u64(p);
let line = LittleEndian::read_u64(&p[PATCH_ID_SIZE..]);
Key {
patch: PatchId(patch),
line: LineId(line),
}
}
unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {
self.cmp(&x)
}
type PageOffsets = std::iter::Empty<u64>;
fn page_offsets(&self) -> Self::PageOffsets {
std::iter::empty()
}
}