refactor(core): move LinearTable stuff into separate file; add iterator for X2dhc -> hilbert
This commit is contained in:
parent
c25c3f11ea
commit
7a54e48a09
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -423,7 +423,7 @@ checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
|
|||
|
||||
[[package]]
|
||||
name = "yglnk-core"
|
||||
version = "0.1.0"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"int-enum",
|
||||
"xxhash-rust",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "yglnk-core"
|
||||
description = "basic on-disk structured data helpers"
|
||||
categories = ["parser-implementations"]
|
||||
version = "0.0.0"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR ISC"
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use super::decode_location;
|
||||
|
||||
/// rotate/flip a quadrant
|
||||
fn rot(n: u32, x: &mut u32, y: &mut u32, rx: bool, ry: bool) {
|
||||
if ry {
|
||||
|
@ -32,6 +34,73 @@ pub fn xy2d(nh: u8, mut x: u32, mut y: u32) -> u32 {
|
|||
.sum()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct X2dhc<'a> {
|
||||
xybits: u8,
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum X2dhcDim {
|
||||
X(u8),
|
||||
Y(u8),
|
||||
}
|
||||
|
||||
impl X2dhcDim {
|
||||
pub fn value(&self) -> u8 {
|
||||
match *self {
|
||||
X2dhcDim::X(x) => x,
|
||||
X2dhcDim::Y(y) => y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> X2dhc<'a> {
|
||||
pub fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
if data.len() < 32 {
|
||||
return None;
|
||||
}
|
||||
let xybits = data[0];
|
||||
if xybits >= 8 {
|
||||
return None;
|
||||
}
|
||||
let exp_len = 1usize.checked_shl(xybits.into())?.checked_mul(16)?;
|
||||
Some(Self {
|
||||
xybits,
|
||||
data: data.get(16..16 + exp_len)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn lookup_internal(data: &'a [u8], xybits2: u8, x: u8, y: u8) -> (u64, u64) {
|
||||
let loc = decode_location(xy2d(xybits2, x.into(), y.into()));
|
||||
let dloc = &data[loc..loc + 16];
|
||||
(
|
||||
u64::from_be_bytes(dloc[0..8].try_into().unwrap()),
|
||||
u64::from_be_bytes(dloc[8..16].try_into().unwrap()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn lookup(&self, x: u8, y: u8) -> (u64, u64) {
|
||||
let xybr = 8 - self.xybits;
|
||||
Self::lookup_internal(self.data, 2 * self.xybits, x >> xybr, y >> xybr)
|
||||
}
|
||||
|
||||
pub fn iter_dim(&self, dim: X2dhcDim) -> impl Iterator<Item = ((u8, u8), (u64, u64))> + 'a {
|
||||
let X2dhc { xybits, data } = *self;
|
||||
let (xybr, xybdup) = (8 - xybits, 2 * xybits);
|
||||
let xy = dim.value() >> xybr;
|
||||
let xyv = xy << xybr;
|
||||
(0u8..=(0xff >> xybr)).map(move |i| {
|
||||
let xy2 = i << xybr;
|
||||
let (x, y) = match dim {
|
||||
X2dhcDim::X(_) => (xyv, xy2),
|
||||
X2dhcDim::Y(_) => (xy2, xyv),
|
||||
};
|
||||
((x, y), Self::lookup_internal(data, xybdup, x, y))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -5,6 +5,7 @@ pub use int_enum::{IntEnum, IntEnumError};
|
|||
|
||||
pub mod hash_table;
|
||||
pub mod hilbert;
|
||||
pub mod linear_table;
|
||||
|
||||
pub const MAGIC: [u8; 4] = [b'Y', b'g', b'L', b'n'];
|
||||
|
||||
|
@ -77,103 +78,6 @@ pub fn trunc_key_at0(key: &[u8]) -> &[u8] {
|
|||
&key[..key_end]
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LinearTableEntry<R> {
|
||||
pub name: R,
|
||||
pub typ: u32,
|
||||
pub location: u32,
|
||||
pub meta: u32,
|
||||
pub rest: R,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LinearTableRef<'a> {
|
||||
cklen: usize,
|
||||
strtab: &'a [u8],
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
pub fn decode_location(location: u32) -> usize {
|
||||
16 * usize::try_from(location).unwrap()
|
||||
}
|
||||
|
||||
impl<'a> LinearTableRef<'a> {
|
||||
pub fn parse(data: &'a [u8], location: u32) -> Option<Self> {
|
||||
let sel = decode_location(location);
|
||||
if data.len() < (sel + 16) {
|
||||
return None;
|
||||
}
|
||||
let sel = &data[sel..];
|
||||
let strtab_link = u32::from_be_bytes(sel[0..4].try_into().unwrap());
|
||||
let entcount = u16::from_be_bytes(sel[4..6].try_into().unwrap());
|
||||
let entsize = u16::from_be_bytes(sel[6..8].try_into().unwrap());
|
||||
let strtab_loc = decode_location(strtab_link);
|
||||
let dataspan = 16..(16 + 16 * usize::from(entsize) * usize::from(entcount));
|
||||
|
||||
if data.len() <= strtab_loc || entsize == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
cklen: 16 * usize::from(entsize),
|
||||
strtab: &data[strtab_loc..],
|
||||
data: sel.get(dataspan)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for LinearTableRef<'a> {
|
||||
type Item = LinearTableEntry<&'a [u8]>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.len() < self.cklen {
|
||||
debug_assert!(self.data.is_empty());
|
||||
return None;
|
||||
}
|
||||
let (i, j) = self.data.split_at(self.cklen);
|
||||
self.data = j;
|
||||
let name = usize::try_from(u32::from_be_bytes(i[0..4].try_into().unwrap())).unwrap();
|
||||
let name = trunc_key_at0(self.strtab.get(name..)?);
|
||||
Some(LinearTableEntry {
|
||||
name,
|
||||
typ: u32::from_be_bytes(i[4..8].try_into().unwrap()),
|
||||
location: u32::from_be_bytes(i[8..12].try_into().unwrap()),
|
||||
meta: u32::from_be_bytes(i[12..16].try_into().unwrap()),
|
||||
rest: &i[16..],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct X2dhc<'a> {
|
||||
xybits: u8,
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> X2dhc<'a> {
|
||||
pub fn parse(data: &'a [u8]) -> Option<Self> {
|
||||
if data.len() < 32 {
|
||||
return None;
|
||||
}
|
||||
let xybits = data[0];
|
||||
if xybits >= 8 {
|
||||
return None;
|
||||
}
|
||||
let exp_len = 1usize.checked_shl(xybits.into())?.checked_mul(16)?;
|
||||
Some(Self {
|
||||
xybits,
|
||||
data: data.get(16..16 + exp_len)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup(&self, x: u8, y: u8) -> (u64, u64) {
|
||||
let xybr = 8 - self.xybits;
|
||||
let (x, y) = (x >> xybr, y >> xybr);
|
||||
let loc = decode_location(hilbert::xy2d(2 * self.xybits, x.into(), y.into()));
|
||||
let dloc = &self.data[loc..loc + 16];
|
||||
(
|
||||
u64::from_be_bytes(dloc[0..8].try_into().unwrap()),
|
||||
u64::from_be_bytes(dloc[8..16].try_into().unwrap()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
64
crates/yglnk-core/src/linear_table.rs
Normal file
64
crates/yglnk-core/src/linear_table.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use super::{decode_location, trunc_key_at0};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Entry<R> {
|
||||
pub name: R,
|
||||
pub typ: u32,
|
||||
pub location: u32,
|
||||
pub meta: u32,
|
||||
pub rest: R,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Ref<'a> {
|
||||
cklen: usize,
|
||||
strtab: &'a [u8],
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Ref<'a> {
|
||||
pub fn parse(data: &'a [u8], location: u32) -> Option<Self> {
|
||||
let sel = decode_location(location);
|
||||
if data.len() < (sel + 16) {
|
||||
return None;
|
||||
}
|
||||
let sel = &data[sel..];
|
||||
let strtab_link = u32::from_be_bytes(sel[0..4].try_into().unwrap());
|
||||
let entcount = u16::from_be_bytes(sel[4..6].try_into().unwrap());
|
||||
let entsize = u16::from_be_bytes(sel[6..8].try_into().unwrap());
|
||||
let strtab_loc = decode_location(strtab_link);
|
||||
let dataspan = 16..(16 + 16 * usize::from(entsize) * usize::from(entcount));
|
||||
|
||||
if data.len() <= strtab_loc || entsize == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
cklen: 16 * usize::from(entsize),
|
||||
strtab: &data[strtab_loc..],
|
||||
data: sel.get(dataspan)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Ref<'a> {
|
||||
type Item = Entry<&'a [u8]>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.len() < self.cklen {
|
||||
debug_assert!(self.data.is_empty());
|
||||
return None;
|
||||
}
|
||||
let (i, j) = self.data.split_at(self.cklen);
|
||||
self.data = j;
|
||||
let name = usize::try_from(u32::from_be_bytes(i[0..4].try_into().unwrap())).unwrap();
|
||||
let name = trunc_key_at0(self.strtab.get(name..)?);
|
||||
Some(Entry {
|
||||
name,
|
||||
typ: u32::from_be_bytes(i[4..8].try_into().unwrap()),
|
||||
location: u32::from_be_bytes(i[8..12].try_into().unwrap()),
|
||||
meta: u32::from_be_bytes(i[12..16].try_into().unwrap()),
|
||||
rest: &i[16..],
|
||||
})
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ fn main() {
|
|||
|
||||
match &cli.command {
|
||||
Command::Linear => {
|
||||
let ltr = yglnk_core::LinearTableRef::parse(data, cli.location)
|
||||
let ltr = yglnk_core::linear_table::Ref::parse(data, cli.location)
|
||||
.expect("unable to parse table header");
|
||||
println!("location\tmeta\t\tname\t\ttyp\t\trest");
|
||||
for i in ltr {
|
||||
|
|
Loading…
Reference in a new issue