yglnk/crates/yglnk-core/src/lib.rs
2023-01-08 09:06:50 +01:00

144 lines
3.6 KiB
Rust

#![no_std]
#![forbid(unsafe_code)]
use int_enum::IntEnum;
pub mod hilbert;
mod ht;
pub use ht::*;
pub const MAGIC: [u8; 4] = [b'Y', b'g', b'L', b'n'];
#[derive(Clone, Copy, Debug, IntEnum)]
#[repr(u32)]
#[rustfmt::skip]
pub enum FileType {
None = 0x0000_0000,
Text = 0x0000_0001,
}
pub struct FileHeader {
pub magic: [u8; 4],
pub generator: u32,
pub typ: u32,
pub version: u32,
}
impl FileHeader {
pub fn decode(data: [u8; 16]) -> Self {
Self {
magic: data[0..4].try_into().unwrap(),
generator: u32::from_be_bytes(data[4..8].try_into().unwrap()),
typ: u32::from_be_bytes(data[8..12].try_into().unwrap()),
version: u32::from_be_bytes(data[12..16].try_into().unwrap()),
}
}
pub fn encode(&self) -> [u8; 16] {
let mut data = [0u8; 16];
data[0..4].copy_from_slice(&self.magic);
data[4..8].copy_from_slice(&u32::to_be_bytes(self.generator));
data[8..12].copy_from_slice(&u32::to_be_bytes(self.typ));
data[12..16].copy_from_slice(&u32::to_be_bytes(self.version));
data
}
}
#[derive(Clone, Copy, Debug, IntEnum)]
#[repr(u32)]
#[rustfmt::skip]
pub enum Type {
PlainText = 0x0000_0000,
NestedText = 0x0000_0001,
StringTable = 0x0000_0010,
LinearPlain = 0x0000_0012,
HashPlain = 0x0000_0020,
HashLink = 0x0000_0021,
X2dhcPlain = 0x0000_0030,
X2dhcLink = 0x0000_0031,
}
#[derive(Clone, Copy, Debug, IntEnum)]
#[repr(u16)]
#[rustfmt::skip]
pub enum Ntt01 {
Div = 0x0000,
Group = 0x0001,
Header = 0x0002,
Quote = 0x0003,
Code = 0x0004,
}
#[derive(Clone, Copy, Debug)]
pub struct LinearTableEntry<R> {
pub name: u32,
pub typ: u32,
pub location: u32,
pub entsize: u16,
pub entcount: u16,
pub rest: R,
}
pub fn linear_table_iter(
data: &[u8],
entsize: u16,
entcount: u16,
) -> impl Iterator<Item = LinearTableEntry<&'_ [u8]>> {
assert!(entsize > 0);
data.chunks(usize::from(entsize) * 16)
.take(entcount.into())
.map(|i| LinearTableEntry {
name: u32::from_be_bytes(i[0..4].try_into().unwrap()),
typ: u32::from_be_bytes(i[4..8].try_into().unwrap()),
location: u32::from_be_bytes(i[8..12].try_into().unwrap()),
entsize: u16::from_be_bytes(i[12..14].try_into().unwrap()),
entcount: u16::from_be_bytes(i[14..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], entsize: u16, entcount: u16) -> Option<Self> {
if entsize != 1 {
return None;
}
let data = data.get(..(16 * usize::from(entcount)))?;
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)?;
if (data.len() - 16) != exp_len {
return None;
}
Some(Self {
xybits,
data: &data[16..],
})
}
pub fn lookup(&self, x: u8, y: u8) -> (u64, u64) {
let xybr = 8 - self.xybits;
let (x, y) = (x >> xybr, y >> xybr);
let loc = 16 * usize::try_from(hilbert::xy2d(2 * self.xybits, x.into(), y.into())).unwrap();
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()),
)
}
}