use std::io::{Write, Read};
use std::fmt;
use smallvec::SmallVec;
use num_traits::{Num, PrimInt, Signed, Unsigned, FromPrimitive, Zero, One, ToPrimitive};
use tree::*;
use point::*;
use super::*;
use super::marker_types::Canonical;
use super::lut::LookupTable;
use lut::ValuesOrRedirect;
use std::collections::HashMap;
type UInt = u32;
type SInt = i32;
const MAGIC: &[u8] = "fast-steiner lookup-table\r\n".as_bytes();
pub fn write_lut<W: Write>(writer: &mut W, lut: &LookupTable) -> Result<(), LUTWriteError> {
let mut trees: Vec<_> = lut.sub_lut_by_degree.iter()
.flat_map(|sub_lut| sub_lut.values.iter())
.filter_map(|v| match v {
ValuesOrRedirect::Values(v) => Some(v),
ValuesOrRedirect::Redirect { .. } => None
})
.flat_map(|v| v.iter())
.map(|v| &v.potential_optimal_steiner_tree)
.collect();
trees.sort_unstable();
println!("Compress {} trees.", trees.len());
let trees = {
let tour: Vec<_> = (0..trees.len()).collect();
let trees: Vec<_> = tour.into_iter()
.map(|i| trees[i])
.collect();
trees
};
let tree_indices: HashMap<_, _> = trees.iter()
.enumerate()
.map(|(i, t)| (*t, i))
.collect();
write_trees(writer, &trees)?;
Ok(())
}
fn write_trees<W: Write>(writer: &mut W, trees: &Vec<&Tree<Canonical>>) -> Result<(), LUTWriteError> {
write_unsigned_integer(writer, trees.len())?;
let empty_tree = Tree::empty_canonical();
let mut prev_tree = &empty_tree;
for current_tree in trees {
let (edge_diff_horiz, edge_diff_vert): (Vec<_>, Vec<_>) = prev_tree.symmetric_difference(current_tree)
.partition(|e| e.is_horizontal());
write_unsigned_integer(writer, edge_diff_horiz.len())?;
write_unsigned_integer(writer, edge_diff_vert.len())?;
for e in edge_diff_horiz {
write_point_u4(writer, e.start())?;
}
for e in edge_diff_vert {
write_point_u4(writer, e.start())?;
}
prev_tree = current_tree;
}
Ok(())
}
fn write_point_u4<W: Write>(writer: &mut W, p: Point<HananCoord>) -> Result<(), LUTWriteError> {
assert!(p.x < 16 && p.y < 16, "edge coordinate out of range for storage");
let nibbles = ((p.x << 4) | (p.y & 0xf)) as u8;
writer.write_all(&[nibbles])?;
Ok(())
}
fn read_point<R: Read>(reader: &mut R) -> Result<Point<HananCoord>, LUTReadError> {
let nibbles = read_byte(reader)?;
let x = nibbles >> 4;
let y = nibbles & 0xf;
Ok(Point::new(x as HananCoord, y as HananCoord))
}
fn read_byte<R: Read>(reader: &mut R) -> Result<u8, LUTReadError> {
let mut b = [0u8];
reader.read_exact(&mut b)?;
Ok(b[0])
}
#[cfg(test)]
fn bits(bit_string: &str) -> Vec<u8> {
bit_string.split_ascii_whitespace()
.map(|s| u8::from_str_radix(s, 2).unwrap())
.collect()
}
#[cfg(test)]
macro_rules! bits {
($x:expr) => {&mut bits($x)[..].as_ref()}
}
#[derive(Debug)]
pub enum LUTReadError {
IOError(std::io::Error),
UnexpectedEndOfFile,
FormatError,
}
impl fmt::Display for LUTReadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use LUTReadError::*;
match self {
LUTReadError::FormatError => write!(f, "illegal table format"),
other => other.fmt(f)
}
}
}
#[derive(Debug)]
pub enum LUTWriteError {
IOError(std::io::Error),
}
impl fmt::Display for LUTWriteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use LUTWriteError::*;
match self {
other => other.fmt(f)
}
}
}
impl From<std::io::Error> for LUTReadError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
std::io::ErrorKind::UnexpectedEof => LUTReadError::UnexpectedEndOfFile,
_ => LUTReadError::IOError(err)
}
}
}
impl From<std::io::Error> for LUTWriteError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
_ => LUTWriteError::IOError(err)
}
}
}
fn read_magic<R: Read>(reader: &mut R) -> Result<(), LUTReadError> {
let mut buf = [0u8; MAGIC.len()];
reader.read_exact(&mut buf)?;
match buf.as_ref() {
MAGIC => Ok(()), _ => {
let s = String::from_utf8_lossy(&buf);
log::error!("wrong file format, magic string is wrong: '{:?}', hex = '{:02x?}'", s, buf);
Err(LUTReadError::FormatError)
} }
}
fn write_magic<W: Write>(writer: &mut W) -> Result<(), LUTWriteError> {
writer.write_all(MAGIC)?;
Ok(())
}
fn read_unsigned_integer<T, R: Read>(reader: &mut R) -> Result<T, LUTReadError>
where T: PrimInt + Zero + FromPrimitive {
let mut bytes = <SmallVec<[u8; 8]>>::new();
for b in reader.bytes() {
let b = b?;
bytes.push(b);
if b & 0x80 == 0 {
break;
}
}
if bytes.last().map(|b| b & 0x80) != Some(0) { Err(LUTReadError::UnexpectedEndOfFile)
} else {
Ok(
bytes.iter()
.rev()
.map(|b| b & 0x7f) .fold(T::zero(), |acc, b| T::from_u8(b).unwrap() + (acc << 7))
)
}
}
#[test]
fn test_read_unsigned_integer() {
assert_eq!(read_unsigned_integer::<u32, _>(bits!("00000000")).unwrap(), 0);
assert_eq!(read_unsigned_integer::<i32, _>(bits!("01111111")).unwrap(), 127);
assert_eq!(read_unsigned_integer::<i32, _>(bits!("10000000 00000001")).unwrap(), 128);
assert_eq!(read_unsigned_integer::<i32, _>(bits!("11111111 01111111")).unwrap(), 16383);
assert_eq!(read_unsigned_integer::<i32, _>(bits!("10000000 10000000 00000001")).unwrap(), 16384);
assert!(read_unsigned_integer::<i32, _>(bits!("")).is_err());
assert!(read_unsigned_integer::<i32, _>(bits!("10000000")).is_err());
}
fn write_unsigned_integer<T, W: Write>(writer: &mut W, value: T) -> Result<(), LUTWriteError>
where T: PrimInt + Unsigned + FromPrimitive + ToPrimitive {
let mut value = value;
let mask = T::from_u8(0x7f).unwrap();
let _0x80 = T::from_u8(0x80).unwrap();
while value > mask {
let lowest = (value & mask).to_u8().unwrap();
writer.write_all(&[0x80 | lowest])?; value = value.shr(7);
}
debug_assert!(value & _0x80 == T::zero());
writer.write_all(&[value.to_u8().unwrap()])?;
Ok(())
}
#[test]
fn test_write_unsigned_integer() {
fn test(num: UInt, expected: Vec<u8>) {
let mut buf = Vec::new();
write_unsigned_integer(&mut buf, num).unwrap();
assert_eq!(buf, expected);
}
test(0, vec![0x00]);
test(1, vec![0x01]);
test(127, vec![0x7f]);
test(128, vec![0x80, 0x01]);
test(16383, vec![0xff, 0x7f]);
test(16384, vec![0x80, 0x80, 0x01]);
}
fn read_signed_integer<T, R: Read>(reader: &mut R) -> Result<T, LUTReadError>
where T: PrimInt + Num + Zero + One + Signed + FromPrimitive {
let u: T = read_unsigned_integer(reader)?;
let sign = u & One::one();
let magnitude = u.unsigned_shr(1);
Ok(
if sign.is_one() {
T::zero() - magnitude
} else {
magnitude
}
)
}
#[test]
fn test_read_signed_integer() {
assert_eq!(read_signed_integer::<i32, _>(bits!("00")).unwrap(), 0);
assert_eq!(read_signed_integer::<i32, _>(bits!("10")).unwrap(), 1);
assert_eq!(read_signed_integer::<i32, _>(bits!("11")).unwrap(), -1);
assert_eq!(read_signed_integer::<i32, _>(bits!("01111110")).unwrap(), 63);
assert_eq!(read_signed_integer::<i32, _>(bits!("10000001 00000001")).unwrap(), -64);
assert_eq!(read_signed_integer::<i32, _>(bits!("11111110 01111111")).unwrap(), 8191);
assert_eq!(read_signed_integer::<i32, _>(bits!("10000001 10000000 00000001")).unwrap(), -8192);
assert!(read_signed_integer::<i32, _>(bits!("")).is_err());
assert!(read_signed_integer::<i32, _>(bits!("10000000")).is_err());
}
fn write_signed_integer<W: Write>(writer: &mut W, value: SInt) -> Result<(), LUTWriteError> {
let (sign, value) = if value < 0 {
(1, -value)
} else {
(0, value)
};
let magnitude = (value << 1) as UInt;
let u = magnitude | sign;
write_unsigned_integer(writer, u)
}
#[test]
fn test_write_signed_integer() {
fn test(num: SInt, expected: Vec<u8>) {
let mut buf = Vec::new();
write_signed_integer(&mut buf, num).unwrap();
assert_eq!(buf, expected);
}
test(0, vec![0x00]);
test(1, vec![0b10]);
test(-1, vec![0b11]);
test(63, vec![0b01111110]);
test(-64, vec![0x81, 0x01]);
test(8191, vec![0b11111110, 0b01111111]);
test(-8192, vec![0b10000001, 0b10000000, 0b1]);
}
#[test]
fn test_write_lut() {
let lut = super::gen_lut::gen_full_lut(4);
let mut buffer = Vec::new();
let write_result = write_lut(&mut buffer, &lut);
assert!(write_result.is_ok());
dbg!(buffer.len());
assert!(buffer.len() < 100);
}