extern crate libreda_db as db;
use num_traits::Zero;
use std::fmt;
use std::io::{Read, Write};
use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
use std::convert::TryFrom;
pub use db::layout::types::{UInt, SInt};
use db::layout::prelude::*;
pub const MAGIC: &[u8] = "%SEMI-OASIS\r\n".as_bytes();
pub const _S_GDS_PROPERTY_NAME: &str = "S_GDS_PROPERTY";
pub const _S_CELL_OFFSET_NAME: &str = "S_CELL_OFFSET";
pub const _S_MAX_SIGNED_INTEGER_WIDTH_NAME: &str = "S_MAX_SIGNED_INTEGER_WIDTH";
pub const _S_MAX_UNSIGNED_INTEGER_WIDTH_NAME: &str = "S_MAX_UNSIGNED_INTEGER_WIDTH";
pub const _S_TOP_CELL_NAME: &str = "S_TOP_CELL";
pub const _S_BOUNDING_BOXES_AVAILABLE_NAME: &str = "S_BOUNDING_BOXES_AVAILABLE";
pub const _S_BOUNDING_BOX_NAME: &str = "S_BOUNDING_BOX";
#[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 OASISReadError {
IOError(std::io::Error),
FormatError,
WrongVersionString,
InvalidResolution(Real),
NameStringEmpty,
NameStringNotAscii,
UnexpectedRecord(UInt),
MixedImplExplCellnameModes,
MixedImplExplPropnameModes,
MixedImplExplTextstringModes,
MixedImplExplPropstringModes,
CellnameIdAlreadyPresent(UInt),
CellnameAlreadyPresent(String),
PropnameIdAlreadyPresent(UInt),
TextStringAlreadyPresent(UInt),
PropStringAlreadyPresent(UInt),
PropStringIdNotFound(UInt),
TextStringIdNotFound(UInt),
CellnameIdNotFound(UInt),
CellNotFound(String),
NoImplicitTextStringDefined,
ModalTextTypeDefined,
ModalTextLayerDefined,
ModalRepetitionNotDefined,
NoImplicitLayerDefined,
NoImplicitDataTypeDefined,
HeightIsPresentForSquare,
NoCellRecordPresent,
ModalGeometryWNotDefined,
ModalGeometryHNotDefined,
ModalLastPropertyNameNotDefined,
ModalLastValueListNotDefined,
ModalPolygonPointListNotDefined,
ModalPathPointListNotDefined,
ModalPathHalfWidthNotDefined,
ModalPathStartExtensionNotDefined,
ModalPathEndExtensionNotDefined,
ModalPlacementCellNotDefined,
IllegalRepetitionType(UInt),
IllegalIntervalType(UInt),
UnknownValidationScheme(UInt),
UnresolvedForwardReferences(Vec<UInt>),
UnexpectedEndOfFile,
}
impl fmt::Display for OASISReadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use OASISReadError::*;
match self {
MixedImplExplCellnameModes => write!(f, "Implicit and explicit CELLNAME modes cannot be mixed."),
CellnameIdAlreadyPresent(id) => write!(f, "CELLNAME record with ID={} is already present.", id),
PropnameIdAlreadyPresent(id) => write!(f, "PROPNAME record with ID={} is already present.", id),
TextStringAlreadyPresent(id) => write!(f, "TEXSTRING record with ID={} is already present.", id),
PropStringAlreadyPresent(id) => write!(f, "PROPSTRING record with ID={} is already present.", id),
PropStringIdNotFound(id) => write!(f, "No PROPSTRING declared for property with ID {}.", id),
CellnameIdNotFound(id) => write!(f, "No CELLNAME declared for cell with ID {}.", id),
TextStringIdNotFound(id) => write!(f, "No TEXTSTRING declared for TEXT with ID {}.", id),
other => other.fmt(f)
}
}
}
#[derive(Debug)]
pub enum OASISWriteError {
IOError(std::io::Error),
FormatError,
NameStringEmpty,
NameStringNotAscii,
DbuIsZero,
}
impl fmt::Display for OASISWriteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use OASISWriteError::*;
match self {
DbuIsZero => write!(f, "Data base unit (dbu) must not be zero."),
NameStringEmpty => write!(f, "Name string cannot be empty."),
NameStringNotAscii => write!(f, "Name string cannot contain non-ascii characters."),
FormatError => write!(f, "Unspecified OASIS write error."),
other => other.fmt(f)
}
}
}
impl From<std::io::Error> for OASISReadError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
std::io::ErrorKind::UnexpectedEof => OASISReadError::UnexpectedEndOfFile,
_ => OASISReadError::IOError(err)
}
}
}
impl From<std::io::Error> for OASISWriteError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
_ => OASISWriteError::IOError(err)
}
}
}
pub fn read_magic<R: Read>(reader: &mut R) -> Result<(), OASISReadError> {
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 because OASIS magic string is wrong: '{:?}', hex = '{:02x?}'", s, buf);
Err(OASISReadError::FormatError)
} }
}
pub fn write_magic<W: Write>(writer: &mut W) -> Result<(), OASISWriteError> {
writer.write_all(MAGIC)?;
Ok(())
}
#[test]
fn test_write_read_magic() {
let mut buf = Vec::new();
write_magic(&mut buf).unwrap();
assert_eq!(buf.len(), 13);
assert!(read_magic(&mut buf.as_slice()).is_ok())
}
pub fn read_byte<R: Read>(reader: &mut R) -> Result<u8, OASISReadError> {
Ok(reader.read_u8()?)
}
pub fn write_byte<W: Write>(writer: &mut W, b: u8) -> Result<(), OASISWriteError> {
writer.write_u8(b)?;
Ok(())
}
pub fn read_unsigned_integer<R: Read>(reader: &mut R) -> Result<UInt, OASISReadError> {
let mut bytes = Vec::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(OASISReadError::UnexpectedEndOfFile)
} else {
Ok(
bytes.iter()
.rev()
.map(|b| b & 0x7f) .fold(0, |acc, b| b as UInt + (acc << 7))
)
}
}
#[test]
fn test_read_unsigned_integer() {
assert_eq!(read_unsigned_integer(bits!("00000000")).unwrap(), 0);
assert_eq!(read_unsigned_integer(bits!("01111111")).unwrap(), 127);
assert_eq!(read_unsigned_integer(bits!("10000000 00000001")).unwrap(), 128);
assert_eq!(read_unsigned_integer(bits!("11111111 01111111")).unwrap(), 16383);
assert_eq!(read_unsigned_integer(bits!("10000000 10000000 00000001")).unwrap(), 16384);
assert!(read_unsigned_integer(bits!("")).is_err());
assert!(read_unsigned_integer(bits!("10000000")).is_err());
}
pub fn write_unsigned_integer<W: Write>(writer: &mut W, value: UInt) -> Result<(), OASISWriteError> {
let mut value = value;
while value > 0x7f {
let lowest = (value & 0x7f) as u8;
writer.write_u8(0x80 | lowest)?; value >>= 7;
}
debug_assert_eq!(value & 0x80, 0);
writer.write_u8(value as u8)?;
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]);
}
pub fn read_signed_integer<R: Read>(reader: &mut R) -> Result<SInt, OASISReadError> {
let u = read_unsigned_integer(reader)?;
let sign = u & 0x1;
let magnitude = (u >> 1) as SInt;
Ok(match sign {
1 => -magnitude,
_ => magnitude
})
}
#[test]
fn test_read_signed_integer() {
assert_eq!(read_signed_integer(bits!("00")).unwrap(), 0);
assert_eq!(read_signed_integer(bits!("10")).unwrap(), 1);
assert_eq!(read_signed_integer(bits!("11")).unwrap(), -1);
assert_eq!(read_signed_integer(bits!("01111110")).unwrap(), 63);
assert_eq!(read_signed_integer(bits!("10000001 00000001")).unwrap(), -64);
assert_eq!(read_signed_integer(bits!("11111110 01111111")).unwrap(), 8191);
assert_eq!(read_signed_integer(bits!("10000001 10000000 00000001")).unwrap(), -8192);
assert!(read_signed_integer(bits!("")).is_err());
assert!(read_signed_integer(bits!("10000000")).is_err());
}
pub fn write_signed_integer<W: Write>(writer: &mut W, value: SInt) -> Result<(), OASISWriteError> {
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]);
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Real {
PositiveWholeNumber(UInt),
NegativeWholeNumber(UInt),
PositiveReciprocal(UInt),
NegativeReciprocal(UInt),
PositiveRatio(UInt, UInt),
NegativeRatio(UInt, UInt),
IEEEFloat32(f32),
IEEEFloat64(f64),
}
impl Real {
pub fn to_f64(self) -> f64 {
use Real::*;
match self {
PositiveWholeNumber(n) => n as f64,
NegativeWholeNumber(n) => -(n as f64),
PositiveReciprocal(n) => 1. / (n as f64),
NegativeReciprocal(n) => -1. / (n as f64),
PositiveRatio(a, b) => (a as f64) / (b as f64),
NegativeRatio(a, b) => -(a as f64) / (b as f64),
IEEEFloat32(f) => f as f64,
IEEEFloat64(f) => f
}
}
pub fn try_to_int(self) -> Option<SInt> {
use Real::*;
match self {
PositiveWholeNumber(n) => Some(n as SInt),
NegativeWholeNumber(n) => Some(-(n as SInt)),
PositiveRatio(n, 1) => Some(n as SInt),
NegativeRatio(n, 1) => Some(-(n as SInt)),
PositiveReciprocal(1) => Some(1),
NegativeReciprocal(1) => Some(-1),
IEEEFloat32(f) => {
if f.fract() == 0. {
Some(f as SInt)
} else {
None
}
}
IEEEFloat64(f) => {
if f.fract() == 0. {
Some(f as SInt)
} else {
None
}
}
_ => None
}
}
pub fn is_integral(&self) -> bool {
use Real::*;
match self {
PositiveWholeNumber(_) | NegativeWholeNumber(_) => true,
_ => false
}
}
pub fn is_rational(&self) -> bool {
use Real::*;
match self {
IEEEFloat32(_) | IEEEFloat64(_) => false,
_ => true
}
}
}
#[test]
fn test_convert_reals() {
debug_assert_eq!(Real::PositiveWholeNumber(2).to_f64(), 2.0);
debug_assert_eq!(Real::NegativeWholeNumber(2).to_f64(), -2.0);
debug_assert_eq!(Real::PositiveReciprocal(2).to_f64(), 0.5);
debug_assert_eq!(Real::NegativeReciprocal(2).to_f64(), -0.5);
debug_assert_eq!(Real::PositiveRatio(2, 4).to_f64(), 0.5);
debug_assert_eq!(Real::NegativeRatio(2, 4).to_f64(), -0.5);
debug_assert_eq!(Real::IEEEFloat32(0.5f32).to_f64(), 0.5f64);
debug_assert_eq!(Real::IEEEFloat64(0.5f64).to_f64(), 0.5f64);
}
pub fn read_real_without_type<R: Read>(reader: &mut R, type_id: UInt) -> Result<Real, OASISReadError> {
match type_id {
0 => Ok(Real::PositiveWholeNumber(read_unsigned_integer(reader)?)),
1 => Ok(Real::NegativeWholeNumber(read_unsigned_integer(reader)?)),
2 => Ok(Real::PositiveReciprocal(read_unsigned_integer(reader)?)),
3 => Ok(Real::NegativeReciprocal(read_unsigned_integer(reader)?)),
4 => {
let nom = read_unsigned_integer(reader)?;
let denom = read_unsigned_integer(reader)?;
if denom == 0 {
log::error!("Denominator of a positive ratio is 0 (ratio = {}/{}).", nom, denom);
Err(OASISReadError::FormatError) } else {
Ok(Real::PositiveRatio(nom, denom))
}
}
5 => {
let nom = read_unsigned_integer(reader)?;
let denom = read_unsigned_integer(reader)?;
if denom == 0 {
log::error!("Denominator of a negative ratio is 0 (ratio = {}/{}).", nom, denom);
Err(OASISReadError::FormatError) } else {
Ok(Real::NegativeRatio(nom, denom))
}
}
6 => Ok(Real::IEEEFloat32(reader.read_f32::<LittleEndian>()?)),
7 => Ok(Real::IEEEFloat64(reader.read_f64::<LittleEndian>()?)),
_ => Err(OASISReadError::FormatError) }
}
pub fn read_real<R: Read>(reader: &mut R) -> Result<Real, OASISReadError> {
let type_id = read_unsigned_integer(reader)?;
read_real_without_type(reader, type_id)
}
#[test]
fn test_read_real() {
assert_eq!(read_real(bits!("00000000 00000000")).unwrap(), Real::PositiveWholeNumber(0));
assert_eq!(read_real(bits!("00000110 00000000 00000000 00000000 00000000")).unwrap(),
Real::IEEEFloat32(0.0));
assert_eq!(read_real(bits!("00000000 00000001")).unwrap(), Real::PositiveWholeNumber(1));
assert_eq!(read_real(bits!("00000110 00000000 00000000 10000000 00111111")).unwrap(),
Real::IEEEFloat32(1.0));
assert_eq!(read_real(bits!("00000011 00000010")).unwrap(), Real::NegativeReciprocal(2));
assert_eq!(read_real(bits!("00000110 00000000 00000000 00000000 10111111")).unwrap(),
Real::IEEEFloat32(-0.5));
assert_eq!(read_real(bits!("00000100 00000101 00010000")).unwrap(), Real::PositiveRatio(5, 16));
assert_eq!(read_real(bits!("00000110 00000000 00000000 10100000 00111110")).unwrap(),
Real::IEEEFloat32(0.3125));
assert_eq!(read_real(bits!("00000010 00000011")).unwrap(), Real::PositiveReciprocal(3));
assert_eq!(read_real(bits!("00000110 10101011 10101010 10101010 00111110")).unwrap(),
Real::IEEEFloat32(1.0 / 3.0));
assert_eq!(read_real(bits!("00000101 00000010 00001101")).unwrap(), Real::NegativeRatio(2, 13));
assert_eq!(read_real(bits!("00000110 11011001 10001001 00011101 10111110")).unwrap(),
Real::IEEEFloat32(-2.0 / 13.0));
}
pub fn write_real<W: Write>(writer: &mut W, value: Real) -> Result<(), OASISWriteError> {
match value {
Real::PositiveWholeNumber(n) => {
write_unsigned_integer(writer, 0)?;
write_unsigned_integer(writer, n)?;
}
Real::NegativeWholeNumber(n) => {
write_unsigned_integer(writer, 1)?;
write_unsigned_integer(writer, n)?;
}
Real::PositiveReciprocal(n) => {
write_unsigned_integer(writer, 2)?;
write_unsigned_integer(writer, n)?;
}
Real::NegativeReciprocal(n) => {
write_unsigned_integer(writer, 3)?;
write_unsigned_integer(writer, n)?;
}
Real::PositiveRatio(d, n) => {
write_unsigned_integer(writer, 4)?;
write_unsigned_integer(writer, d)?;
write_unsigned_integer(writer, n)?;
}
Real::NegativeRatio(d, n) => {
write_unsigned_integer(writer, 5)?;
write_unsigned_integer(writer, d)?;
write_unsigned_integer(writer, n)?;
}
Real::IEEEFloat32(n) => {
write_unsigned_integer(writer, 6)?;
writer.write_f32::<LittleEndian>(n)?;
}
Real::IEEEFloat64(n) => {
write_unsigned_integer(writer, 7)?;
writer.write_f64::<LittleEndian>(n)?;
}
}
Ok(())
}
pub fn read_byte_string<R: Read>(reader: &mut R) -> Result<Vec<u8>, OASISReadError> {
let length = read_unsigned_integer(reader)?;
let mut result = Vec::new();
for _ in 0..length {
result.push(reader.read_u8()?);
}
Ok(result)
}
pub fn write_byte_string<W: Write>(writer: &mut W, value: &[u8]) -> Result<(), OASISWriteError> {
write_unsigned_integer(writer, value.len() as UInt)?;
writer.write_all(value)?;
Ok(())
}
pub fn bytes_to_ascii_string(bytes: Vec<u8>) -> Option<String> {
let is_all_ascii = bytes.iter().all(|&c| 0x20 <= c && c <= 0x7e);
if is_all_ascii {
Some(String::from_utf8(bytes).unwrap())
} else {
None
}
}
pub fn read_ascii_string<R: Read>(reader: &mut R) -> Result<String, OASISReadError> {
let str = read_byte_string(reader)?;
let ascii_str = bytes_to_ascii_string(str);
if let Some(ascii_str) = ascii_str {
Ok(ascii_str)
} else {
log::error!("Failed to read ASCII string.");
Err(OASISReadError::FormatError) }
}
pub fn write_ascii_string<W: Write>(writer: &mut W, value: &[u8]) -> Result<(), OASISWriteError> {
let is_all_ascii = value.iter().all(|&c| 0x20 <= c && c <= 0x7e);
if is_all_ascii {
write_byte_string(writer, value)?;
Ok(())
} else {
Err(OASISWriteError::FormatError) }
}
pub fn bytes_to_name_string(bytes: Vec<u8>) -> Option<String> {
let is_all_ascii = bytes.iter().all(|&c| 0x21 <= c && c <= 0x7e);
if is_all_ascii && !bytes.is_empty() {
Some(String::from_utf8(bytes).unwrap())
} else {
None
}
}
pub fn read_name_string<R: Read>(reader: &mut R) -> Result<String, OASISReadError> {
let str = read_byte_string(reader)?;
if str.is_empty() {
Err(OASISReadError::NameStringEmpty)
} else {
let name_str = bytes_to_name_string(str);
if let Some(name_str) = name_str {
Ok(name_str)
} else {
Err(OASISReadError::NameStringNotAscii)
}
}
}
pub fn write_name_string<W: Write>(writer: &mut W, value: &[u8]) -> Result<(), OASISWriteError> {
if value.is_empty() {
Err(OASISWriteError::NameStringEmpty)
} else {
let is_all_ascii = value.iter().all(|&c| 0x21 <= c && c <= 0x7e);
if is_all_ascii {
write_byte_string(writer, value)?;
Ok(())
} else {
Err(OASISWriteError::NameStringNotAscii)
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum Delta {}
pub fn read_1delta<R: Read>(reader: &mut R) -> Result<SInt, OASISReadError> {
read_signed_integer(reader)
}
pub fn write_1delta<W: Write>(writer: &mut W, delta: SInt) -> Result<(), OASISWriteError> {
write_signed_integer(writer, delta)
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum Delta2 {
East(UInt),
North(UInt),
West(UInt),
South(UInt),
}
impl TryFrom<Vector<SInt>> for Delta2 {
type Error = ();
fn try_from(v: Vector<SInt>) -> Result<Self, Self::Error> {
match (v.x, v.y) {
(0, y) if y < 0 => Ok(Delta2::South(-y as UInt)),
(0, y) => Ok(Delta2::North(y as UInt)),
(x, 0) if x < 0 => Ok(Delta2::West(-x as UInt)),
(x, 0) => Ok(Delta2::East(x as UInt)),
_ => Err(())
}
}
}
impl Into<Vector<SInt>> for Delta2 {
fn into(self) -> Vector<SInt> {
match self {
Delta2::East(m) => Vector::new(m as SInt, 0),
Delta2::North(m) => Vector::new(0, m as SInt),
Delta2::West(m) => Vector::new(-(m as SInt), 0),
Delta2::South(m) => Vector::new(0, -(m as SInt)),
}
}
}
pub fn read_2delta<R: Read>(reader: &mut R) -> Result<Delta2, OASISReadError> {
let u = read_unsigned_integer(reader)?;
let dir = u & 0b11;
let magnitude = u >> 2;
let d = match dir {
0 => Delta2::East(magnitude),
1 => Delta2::North(magnitude),
2 => Delta2::West(magnitude),
3 => Delta2::South(magnitude),
_ => unreachable!()
};
Ok(d)
}
pub fn write_2delta<W: Write>(writer: &mut W, d: Delta2) -> Result<(), OASISWriteError> {
let u = match d {
Delta2::East(m) => (m << 2) | 0b00,
Delta2::North(m) => (m << 2) | 0b01,
Delta2::West(m) => (m << 2) | 0b10,
Delta2::South(m) => (m << 2) | 0b11,
};
write_unsigned_integer(writer, u)
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum Delta3 {
East(UInt),
North(UInt),
West(UInt),
South(UInt),
NorthEast(UInt),
NorthWest(UInt),
SouthWest(UInt),
SouthEast(UInt),
}
impl TryFrom<Vector<SInt>> for Delta3 {
type Error = ();
fn try_from(v: Vector<SInt>) -> Result<Self, Self::Error> {
match (v.x, v.y) {
(0, y) if y < 0 => Ok(Delta3::South(-y as UInt)),
(0, y) => Ok(Delta3::North(y as UInt)),
(x, 0) if x < 0 => Ok(Delta3::West(-x as UInt)),
(x, 0) => Ok(Delta3::East(x as UInt)),
(x, y) if x == y && x < 0 => Ok(Delta3::SouthWest(-x as UInt)),
(x, y) if x == y => Ok(Delta3::NorthEast(x as UInt)),
(x, y) if y == -x && x < 0 => Ok(Delta3::NorthWest(y as UInt)),
(x, y) if y == -x => Ok(Delta3::SouthEast(x as UInt)),
_ => Err(())
}
}
}
impl Into<Vector<SInt>> for Delta3 {
fn into(self) -> Vector<SInt> {
match self {
Delta3::East(m) => Vector::new(m as SInt, 0),
Delta3::North(m) => Vector::new(0, m as SInt),
Delta3::West(m) => Vector::new(-(m as SInt), 0),
Delta3::South(m) => Vector::new(0, -(m as SInt)),
Delta3::NorthEast(m) => Vector::new(m as SInt, m as SInt),
Delta3::NorthWest(m) => Vector::new(-(m as SInt), m as SInt),
Delta3::SouthWest(m) => Vector::new(-(m as SInt), -(m as SInt)),
Delta3::SouthEast(m) => Vector::new(m as SInt, -(m as SInt)),
}
}
}
impl Delta3 {
fn decode_from_uint(u: UInt) -> Self {
let dir = u & 0b111; let m = u >> 3;
match dir {
0 => Delta3::East(m),
1 => Delta3::North(m),
2 => Delta3::West(m),
3 => Delta3::South(m),
4 => Delta3::NorthEast(m),
5 => Delta3::NorthWest(m),
6 => Delta3::SouthWest(m),
7 => Delta3::SouthEast(m),
_ => unreachable!()
}
}
fn encode_as_uint(self) -> UInt {
match self {
Delta3::East(m) => (m << 3) | 0,
Delta3::North(m) => (m << 3) | 1,
Delta3::West(m) => (m << 3) | 2,
Delta3::South(m) => (m << 3) | 3,
Delta3::NorthEast(m) => (m << 3) | 4,
Delta3::NorthWest(m) => (m << 3) | 5,
Delta3::SouthWest(m) => (m << 3) | 6,
Delta3::SouthEast(m) => (m << 3) | 7,
}
}
}
pub fn read_3delta<R: Read>(reader: &mut R) -> Result<Delta3, OASISReadError> {
let u = read_unsigned_integer(reader)?;
Ok(Delta3::decode_from_uint(u))
}
pub fn write_3delta<W: Write>(writer: &mut W, d: Delta3) -> Result<(), OASISWriteError> {
write_unsigned_integer(writer, d.encode_as_uint())
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum DeltaG {
Delta3(Delta3),
Arbitrary(SInt, SInt),
}
impl From<Vector<SInt>> for DeltaG {
fn from(v: Vector<SInt>) -> Self {
Delta3::try_from(v)
.map(|d| DeltaG::Delta3(d))
.unwrap_or(DeltaG::Arbitrary(v.x, v.y))
}
}
impl Into<Vector<SInt>> for DeltaG {
fn into(self) -> Vector<SInt> {
match self {
DeltaG::Delta3(d) => d.into(),
DeltaG::Arbitrary(x, y) => Vector::new(x, y)
}
}
}
pub fn read_gdelta<R: Read>(reader: &mut R) -> Result<DeltaG, OASISReadError> {
let u = read_unsigned_integer(reader)?;
let gdelta_type = u & 0b1;
let d = if gdelta_type == 0 {
let d3 = Delta3::decode_from_uint(u >> 1);
DeltaG::Delta3(d3)
} else {
let x_sign = u & 0b10;
let x_mag = (u >> 2) as SInt;
let x = if x_sign == 0 { x_mag } else { -x_mag };
let y = read_signed_integer(reader)?;
DeltaG::Arbitrary(x, y)
};
Ok(d)
}
pub fn write_gdelta<W: Write>(writer: &mut W, d: DeltaG) -> Result<(), OASISWriteError> {
match d {
DeltaG::Delta3(d3) => {
let u = d3.encode_as_uint() << 1;
write_unsigned_integer(writer, u)?;
}
DeltaG::Arbitrary(x, y) => {
let ux = if x < 0 {
let x_mag = -x as UInt;
(x_mag << 2) | 0b11
} else {
let x_mag = x as UInt;
(x_mag << 2) | 0b01
};
write_unsigned_integer(writer, ux)?; write_signed_integer(writer, y)?; }
};
Ok(())
}
#[test]
fn test_read_delta_encodings() {
assert_eq!(read_1delta(bits!("11111001 00100011")).unwrap(), -2300);
assert_eq!(read_1delta(bits!("11111000 00100011")).unwrap(), 2300);
assert_eq!(read_2delta(bits!("10011000 00101010")).unwrap(), Delta2::East(1350));
assert_eq!(read_2delta(bits!("10011011 00101010")).unwrap(), Delta2::South(1350));
assert_eq!(read_3delta(bits!("11001101 00000001")).unwrap(), Delta3::NorthWest(25));
assert_eq!(read_3delta(bits!("11010111 00000111")).unwrap(), Delta3::SouthEast(122));
assert_eq!(read_gdelta(bits!("11101001 00000011 01111010")).unwrap(), DeltaG::Arbitrary(122, 61));
assert_eq!(read_gdelta(bits!("11101100 00000101")).unwrap(), DeltaG::Delta3(Delta3::SouthWest(46)));
assert_eq!(read_gdelta(bits!("10111011 00000001 10110111 00001111")).unwrap(), DeltaG::Arbitrary(-46, -987));
}
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
pub struct RegularRepetition {
a: Vector<SInt>,
b: Vector<SInt>,
n: UInt,
m: UInt,
}
impl RegularRepetition {
pub fn new(a: Vector<SInt>, b: Vector<SInt>, n: UInt, m: UInt) -> Self {
return RegularRepetition { a, b, n, m };
}
pub fn iter(self) -> impl Iterator<Item=Vector<SInt>> {
(0..self.m).flat_map(move |j| {
(0..self.n).map(move |i| self.a * i as SInt + self.b * j as SInt)
})
}
pub fn len(&self) -> usize {
(self.n * self.m) as usize
}
}
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct IrregularRepetition {
offsets: Vec<Vector<SInt>>
}
impl IrregularRepetition {
fn new(offsets: Vec<Vector<SInt>>) -> Self {
assert!(offsets.len() >= 2);
if let Some(first) = offsets.first() {
assert!(first.is_zero())
}
return IrregularRepetition { offsets };
}
pub fn iter(&self) -> impl Iterator<Item=&Vector<SInt>> {
self.offsets.iter()
}
pub fn len(&self) -> usize {
self.offsets.len()
}
}
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum Repetition {
ReusePrevious,
Regular(RegularRepetition),
Irregular(IrregularRepetition),
}
pub fn read_repetition<R: Read>(reader: &mut R) -> Result<Repetition, OASISReadError> {
let repetition_type = read_unsigned_integer(reader)?;
match repetition_type {
0 => {
Ok(Repetition::ReusePrevious)
}
1 => {
let x_dimension = read_unsigned_integer(reader)?;
let y_dimension = read_unsigned_integer(reader)?;
let x_space = read_unsigned_integer(reader)? as SInt;
let y_space = read_unsigned_integer(reader)? as SInt;
let n = x_dimension + 2;
let m = y_dimension + 2;
Ok(Repetition::Regular(
RegularRepetition::new((x_space, 0).into(), (0, y_space).into(), n, m)
))
}
2 => {
let x_dimension = read_unsigned_integer(reader)?;
let x_space = read_unsigned_integer(reader)? as SInt;
let n = x_dimension + 2;
Ok(Repetition::Regular(
RegularRepetition::new((x_space, 0).into(), (0, 0).into(), n, 1)
))
}
3 => {
let y_dimension = read_unsigned_integer(reader)?;
let y_space = read_unsigned_integer(reader)? as SInt;
let m = y_dimension + 2;
Ok(Repetition::Regular(
RegularRepetition::new((0, 0).into(), (0, y_space).into(), 1, m)
))
}
4 | 5 => {
let x_dimension = read_unsigned_integer(reader)?;
let grid = if repetition_type == 5 { read_unsigned_integer(reader)? } else { 1 } as SInt;
let n = x_dimension + 2;
let mut offsets = Vec::new();
offsets.reserve(n as usize); let mut accumulator = Vector::zero();
offsets.push(accumulator);
for _ in 1..n {
let spacing = read_unsigned_integer(reader)? as SInt;
let diff = (spacing * grid, 0).into();
accumulator += diff;
offsets.push(accumulator);
}
Ok(
Repetition::Irregular(IrregularRepetition::new(offsets))
)
}
6 | 7 => {
let y_dimension = read_unsigned_integer(reader)?;
let grid = if repetition_type == 7 { read_unsigned_integer(reader)? } else { 1 } as SInt;
let m = y_dimension + 2;
let mut offsets = Vec::new();
offsets.reserve(m as usize); let mut accumulator = Vector::zero();
offsets.push(accumulator);
for _ in 1..m {
let spacing = read_unsigned_integer(reader)? as SInt;
let diff = (0, spacing * grid).into();
accumulator += diff;
offsets.push(accumulator);
}
Ok(
Repetition::Irregular(IrregularRepetition::new(offsets))
)
}
8 => {
let n_dimension = read_unsigned_integer(reader)?;
let m_dimension = read_unsigned_integer(reader)?;
let n = n_dimension + 2;
let m = m_dimension + 2;
let n_displacement = read_gdelta(reader)?; let m_displacement = read_gdelta(reader)?;
let a = n_displacement.into();
let b = m_displacement.into();
Ok(
Repetition::Regular(RegularRepetition::new(a, b, n, m))
)
}
9 => {
let dimension = read_unsigned_integer(reader)?;
let displacement = read_gdelta(reader)?;
let d = displacement.into();
let p = dimension + 2;
Ok(
Repetition::Regular(RegularRepetition::new(d, Vector::zero(), p, 1))
)
}
10 | 11 => {
let dimension = read_unsigned_integer(reader)?;
let grid = if repetition_type == 11 { read_unsigned_integer(reader)? } else { 1 } as SInt;
let p = dimension + 2;
let mut offsets = Vec::new();
offsets.reserve(p as usize); let mut accumulator = Vector::zero();
offsets.push(accumulator);
for _ in 1..p {
let d: Vector<SInt> = read_gdelta(reader)?.into();
accumulator += d * grid;
offsets.push(accumulator)
}
Ok(
Repetition::Irregular(IrregularRepetition::new(offsets))
)
}
t => Err(OASISReadError::IllegalRepetitionType(t))
}
}
fn gcd_euclid<T: num_traits::PrimInt>(a: T, b: T) -> T {
let mut a = a;
let mut b = b;
while !b.is_zero() {
let t = b;
b = a % b;
a = t;
}
a
}
#[test]
fn test_gcd() {
assert_eq!(gcd_euclid(0, 0), 0);
assert_eq!(gcd_euclid(0, 1), 1);
assert_eq!(gcd_euclid(1, 0), 1);
assert_eq!(gcd_euclid(2, 4), 2);
assert_eq!(gcd_euclid(14, 21), 7);
}
pub fn write_repetition<W: Write>(writer: &mut W, repetition: &Repetition) -> Result<(), OASISWriteError> {
match repetition {
Repetition::ReusePrevious => {
write_unsigned_integer(writer, 0)?;
}
Repetition::Regular(rep) => {
let RegularRepetition { a, b, n, m } = *rep;
match (a, b, n, m) {
(_, _, 0, _) | (_, _, _, 0) => {
return Err(OASISWriteError::FormatError);
}
(diff, _, p, 1) | (_, diff, 1, p) => {
if p < 2 {
return Err(OASISWriteError::FormatError);
}
let dimension = p - 2;
match (diff.x, diff.y) {
(x, 0) if x >= 0 => {
write_unsigned_integer(writer, 2)?;
write_unsigned_integer(writer, dimension)?;
write_unsigned_integer(writer, x as UInt)?;
}
(0, y) if y >= 0 => {
write_unsigned_integer(writer, 3)?;
write_unsigned_integer(writer, dimension)?;
write_unsigned_integer(writer, y as UInt)?;
}
(_x, _y) => {
write_unsigned_integer(writer, 9)?;
write_unsigned_integer(writer, dimension)?;
write_gdelta(writer, diff.into())?;
}
}
}
(a, b, n, m) => {
if n < 2 || m < 2 {
return Err(OASISWriteError::FormatError);
}
let x_dimension = n - 2;
let y_dimension = m - 2;
match ((a.x, a.y), (b.x, b.y)) {
((x_space, 0), (0, y_space))
| ((0, y_space), (x_space, 0))
if x_space >= 0 || y_space >= 0 => {
write_unsigned_integer(writer, 1)?;
write_unsigned_integer(writer, x_dimension)?;
write_unsigned_integer(writer, y_dimension)?;
write_unsigned_integer(writer, x_space as UInt)?;
write_unsigned_integer(writer, y_space as UInt)?;
}
_ => {
write_unsigned_integer(writer, 8)?;
write_unsigned_integer(writer, x_dimension)?;
write_unsigned_integer(writer, y_dimension)?;
write_gdelta(writer, a.into())?;
write_gdelta(writer, b.into())?;
}
}
}
}
}
Repetition::Irregular(irep) => {
if irep.len() < 2 {
return Err(OASISWriteError::FormatError);
}
let dimension = irep.len() as UInt - 2;
let mut gcd_x = 0;
let mut gcd_y = 0;
let mut is_all_xstep_positive = true;
let mut is_all_ystep_positive = true;
let mut v_prev = None;
for &v in irep.iter() {
gcd_x = gcd_euclid(gcd_x, v.x);
gcd_y = gcd_euclid(gcd_y, v.y);
if let Some(prev) = v_prev {
let diff = v - prev;
if diff.x < 0 {
is_all_xstep_positive = false;
}
if diff.y < 0 {
is_all_ystep_positive = false;
}
}
v_prev = Some(v);
}
let gcd = gcd_euclid(gcd_x, gcd_y);
debug_assert!(gcd >= 0);
let grid = if gcd == 0 { 1 } else { gcd } as UInt;
let is_x_coord_all_zero = gcd_x == 0; let is_y_coord_all_zero = gcd_y == 0;
if is_y_coord_all_zero && is_all_xstep_positive {
if grid == 1 {
write_unsigned_integer(writer, 4)?;
write_unsigned_integer(writer, dimension)?;
} else {
write_unsigned_integer(writer, 5)?;
write_unsigned_integer(writer, dimension)?;
write_unsigned_integer(writer, grid)?;
}
for (a, b) in irep.iter().zip(irep.iter().skip(1)) {
let diff = b.x - a.x;
debug_assert!(diff >= 0);
debug_assert_eq!(diff as UInt % grid, 0);
write_unsigned_integer(writer, diff as UInt / grid)?;
}
} else if is_x_coord_all_zero && is_all_ystep_positive {
if grid == 1 {
write_unsigned_integer(writer, 6)?;
write_unsigned_integer(writer, dimension)?;
} else {
write_unsigned_integer(writer, 7)?;
write_unsigned_integer(writer, dimension)?;
write_unsigned_integer(writer, grid)?;
}
for (a, b) in irep.iter().zip(irep.iter().skip(1)) {
let diff = b.y - a.y;
debug_assert!(diff >= 0);
debug_assert_eq!(diff as UInt % grid, 0);
write_unsigned_integer(writer, diff as UInt / grid)?;
}
} else {
if grid == 1 {
write_unsigned_integer(writer, 10)?;
write_unsigned_integer(writer, dimension)?;
} else {
write_unsigned_integer(writer, 11)?;
write_unsigned_integer(writer, dimension)?;
write_unsigned_integer(writer, grid)?;
}
let grid = grid as SInt;
for (a, b) in irep.iter().zip(irep.iter().skip(1)) {
let diff = *b - *a;
debug_assert_eq!(diff.x % grid, 0);
debug_assert_eq!(diff.y % grid, 0);
let diff = diff / grid;
write_gdelta(writer, diff.into())?;
}
}
}
};
Ok(())
}
#[test]
fn test_write_read_repetition() {
fn test(rep: Repetition) {
let mut buf = Vec::new();
write_repetition(&mut buf, &rep).unwrap();
let rep2 = read_repetition(&mut buf[..].as_ref()).unwrap();
assert_eq!(rep, rep2);
}
test(Repetition::ReusePrevious);
test(Repetition::Regular(
RegularRepetition::new((1, 0).into(), (0, 2).into(), 7, 3)
));
test(Repetition::Regular(
RegularRepetition::new((1, 0).into(), (0, 0).into(), 7, 1)
));
test(Repetition::Regular(
RegularRepetition::new((0, 0).into(), (0, 1).into(), 1, 7)
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (1, 0)].iter().map(|t| t.into()).collect())
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (200, 0), (800, 0)].iter().map(|t| t.into()).collect())
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (0, 1)].iter().map(|t| t.into()).collect())
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (0, 200), (0, 800)].iter().map(|t| t.into()).collect())
));
test(Repetition::Regular(
RegularRepetition::new((-1, 0).into(), (0, 2).into(), 7, 3)
));
test(Repetition::Regular(
RegularRepetition::new((1, 2).into(), (2, 3).into(), 7, 3)
));
test(Repetition::Regular(
RegularRepetition::new((1, 2).into(), (0, 0).into(), 7, 1)
));
test(Repetition::Regular(
RegularRepetition::new((-1, 0).into(), (0, 0).into(), 7, 1)
));
test(Repetition::Regular(
RegularRepetition::new((0, -1).into(), (0, 0).into(), 7, 1)
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (0, 1), (1, 0), (1, 2)].iter().map(|t| t.into()).collect())
));
test(Repetition::Irregular(
IrregularRepetition::new([(0, 0), (0, 100), (100, 0), (100, 200)].iter().map(|t| t.into()).collect())
));
}
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum PointList {
ImplicitManhattanVerticalFirst(Vec<SInt>),
ImplicitManhattanHorizontalFirst(Vec<SInt>),
ExplicitManhattan(Vec<Delta2>),
ExplicitOctangularManhattan(Vec<Delta3>),
Explicit(Vec<DeltaG>),
ExplicitDouble(Vec<DeltaG>),
}
impl PointList {
pub fn _from_points_compressed(_offset: Vector<SInt>, _points: &Vec<Vector<SInt>>) -> PointList {
unimplemented!()
}
pub fn from_points_explicit(points: &Vec<Point<SInt>>) -> PointList {
let (_, diffs) = points.iter().fold((None, Vec::new()),
|(prev, mut acc), ¤t| {
if let Some(prev) = prev {
let diff = current - prev;
acc.push(DeltaG::from(diff))
}
(Some(current), acc)
});
PointList::Explicit(diffs)
}
pub fn points(&self, offset: Vector<SInt>, for_polygon: bool) -> Vec<Point<SInt>> {
let implicit_manhattan_points = |diffs: &Vec<SInt>, vertical: bool| {
let mut points: Vec<Point<_>> = Vec::new();
if for_polygon {
debug_assert!(diffs.len() >= 2);
}
points.reserve(diffs.len() + 2);
let mut accumulator = Point::from(offset);
points.push(accumulator);
let mut vertical = vertical;
for &d in diffs {
let d = if vertical { (d, 0) } else { (0, d) };
accumulator += Vector::from(d);
points.push(accumulator);
vertical = !vertical;
}
if for_polygon {
let second_last = points.last().unwrap();
let last = if vertical {
(0, second_last.y)
} else {
(second_last.x, 0)
};
points.push(last.into());
}
points
};
match self {
PointList::ImplicitManhattanVerticalFirst(diffs) => {
implicit_manhattan_points(diffs, true)
}
PointList::ImplicitManhattanHorizontalFirst(diffs) => {
implicit_manhattan_points(diffs, false)
}
PointList::ExplicitManhattan(diffs) => {
let mut points = Vec::new();
points.reserve(diffs.len() + 1);
let mut accumulator = Point::zero();
points.push(accumulator);
for &d in diffs {
let v: Vector<_> = d.into();
accumulator += v;
points.push(accumulator);
}
points
}
PointList::ExplicitOctangularManhattan(diffs) => {
let mut points = Vec::new();
points.reserve(diffs.len() + 1);
let mut accumulator = Point::from(offset);
points.push(accumulator);
for &d in diffs {
let v: Vector<_> = d.into();
accumulator += v;
points.push(accumulator);
}
points
}
PointList::Explicit(diffs) => {
let mut points = Vec::new();
points.reserve(diffs.len() + 1);
let mut accumulator = Point::from(offset);
points.push(accumulator);
for &d in diffs {
let v: Vector<_> = d.into();
accumulator += v;
points.push(accumulator);
}
points
}
PointList::ExplicitDouble(ddiffs) => {
let mut points = Vec::new();
points.reserve(ddiffs.len() + 1);
let mut accumulator1 = Point::zero();
let mut accumulator2 = Point::from(offset);
points.push(accumulator2);
for &d in ddiffs {
let v: Vector<_> = d.into();
accumulator1 += v;
accumulator2 += accumulator1;
points.push(accumulator2)
}
points
}
}
}
}
#[test]
fn test_pointlist_from_points_to_points() {
let arbitrary: Vec<Point<_>> = vec![(1, 2), (7, 8), (-100, -200), (0, 0), (1, 1), (2, 2)]
.iter().map(|t| t.into()).collect();
let point_list = PointList::from_points_explicit(&arbitrary);
let offset = arbitrary.first().unwrap().v();
let back = point_list.points(offset, false);
assert_eq!(back, arbitrary)
}
pub fn read_point_list<R: Read>(reader: &mut R) -> Result<PointList, OASISReadError> {
let pointlist_type = read_unsigned_integer(reader)?;
let vertex_count = read_unsigned_integer(reader)?;
match pointlist_type {
0 | 1 => {
let mut deltas = Vec::new();
deltas.reserve(vertex_count as usize);
for _ in 0..vertex_count {
deltas.push(read_1delta(reader)?);
}
if pointlist_type == 0 {
Ok(PointList::ImplicitManhattanVerticalFirst(deltas))
} else {
Ok(PointList::ImplicitManhattanHorizontalFirst(deltas))
}
}
2 => {
let mut deltas = Vec::new();
deltas.reserve(vertex_count as usize);
for _ in 0..vertex_count {
deltas.push(read_2delta(reader)?);
}
Ok(PointList::ExplicitManhattan(deltas))
}
3 => {
let mut deltas = Vec::new();
deltas.reserve(vertex_count as usize);
for _ in 0..vertex_count {
deltas.push(read_3delta(reader)?);
}
Ok(PointList::ExplicitOctangularManhattan(deltas))
}
4 | 5 => {
let mut deltas = Vec::new();
deltas.reserve(vertex_count as usize);
for _ in 0..vertex_count {
deltas.push(read_gdelta(reader)?);
}
if pointlist_type == 4 {
Ok(PointList::Explicit(deltas))
} else {
Ok(PointList::ExplicitDouble(deltas))
}
}
_ => {
log::error!("Invalid point-list type (must be in the range 0..5): {}", pointlist_type);
Err(OASISReadError::FormatError) }
}
}
#[test]
fn test_read_pointlist() {
fn points(v: Vec<(SInt, SInt)>) -> Vec<Point<SInt>> {
v.iter().map(|c| c.into()).collect()
}
fn test(bitstring: &str, expected_points: Vec<(SInt, SInt)>) {
let pointlist = read_point_list(bits!(bitstring)).unwrap();
assert_eq!(pointlist.points(Vector::zero(), true), points(expected_points));
}
test("00000000 00000100 00001100 00001000 00010001 00000101",
vec![(0, 0), (6, 0), (6, 4), (-2, 4), (-2, 2), (0, 2)],
);
test("00000001 00000100 00010001 00000100 00000100 00000100",
vec![(0, 0), (0, -8), (2, -8), (2, -6), (4, -6), (4, 0)],
);
test("00000010 00000101 00100000 00011001 00010010 00001011 00010010",
vec![(0, 0), (8, 0), (8, 6), (4, 6), (4, 4), (0, 4)],
);
test("00000011 00000100 00010101 00100001 00110000 00010011",
vec![(0, 0), (-2, 2), (-2, 6), (4, 6), (4, 4)],
);
test("00000100 00000010 01000100 00001001 00001101",
vec![(0, 0), (-4, 0), (-2, -6)],
);
test("00000101 00001001 00000001 00000011 00101001 00000000 00000001 00000100 00000001 00000011 00000001 00000011 00101011 00000100 00101011 00000000 00000001 00000011 00000001 00000011",
vec![(0, 0), (0, -1), (10, -2), (20, -1), (30, -1), (40, -2), (40, -1), (30, 0), (20, 0), (10, -1)],
);
}
pub fn write_pointlist<W: Write>(writer: &mut W, pointlist: &PointList) -> Result<(), OASISWriteError> {
let (pointlist_type, length) = match pointlist {
PointList::ImplicitManhattanVerticalFirst(v) => (0, v.len()),
PointList::ImplicitManhattanHorizontalFirst(v) => (1, v.len()),
PointList::ExplicitManhattan(v) => (2, v.len()),
PointList::ExplicitOctangularManhattan(v) => (3, v.len()),
PointList::Explicit(v) => (4, v.len()),
PointList::ExplicitDouble(v) => (5, v.len()),
};
write_unsigned_integer(writer, pointlist_type)?;
write_unsigned_integer(writer, length as UInt)?;
match pointlist {
PointList::ImplicitManhattanVerticalFirst(v)
| PointList::ImplicitManhattanHorizontalFirst(v) => {
for &x in v {
write_1delta(writer, x)?;
}
}
PointList::ExplicitManhattan(v) => {
for &x in v {
write_2delta(writer, x)?;
}
}
PointList::ExplicitOctangularManhattan(v) => {
for &x in v {
write_3delta(writer, x)?;
}
}
PointList::Explicit(v) | PointList::ExplicitDouble(v) => {
for &x in v {
write_gdelta(writer, x)?;
}
}
};
Ok(())
}
#[derive(PartialEq, Clone, Debug)]
pub enum PropertyValue {
Real(Real),
UInt(UInt),
SInt(SInt),
AString(String),
BString(Vec<u8>),
NString(String),
AStringRef(UInt),
BStringRef(UInt),
NStringRef(UInt), }
pub fn read_property_value<R: Read>(reader: &mut R) -> Result<PropertyValue, OASISReadError> {
let propertyvalue_type = read_unsigned_integer(reader)?;
match propertyvalue_type {
t @ 0..=7 =>
Ok(PropertyValue::Real(read_real_without_type(reader, t)?)),
8 => Ok(PropertyValue::UInt(read_unsigned_integer(reader)?)),
9 => Ok(PropertyValue::SInt(read_signed_integer(reader)?)),
10 => Ok(PropertyValue::AString(read_ascii_string(reader)?)),
11 => Ok(PropertyValue::BString(read_byte_string(reader)?)),
12 => Ok(PropertyValue::NString(read_name_string(reader)?)),
13 => Ok(PropertyValue::AStringRef(read_unsigned_integer(reader)?)),
14 => Ok(PropertyValue::BStringRef(read_unsigned_integer(reader)?)),
15 => Ok(PropertyValue::NStringRef(read_unsigned_integer(reader)?)),
_ => Err(OASISReadError::FormatError)
}
}
pub fn _write_property_value<W: Write>(writer: &mut W, property_value: &PropertyValue) -> Result<(), OASISWriteError> {
match property_value {
PropertyValue::Real(r) => write_real(writer, *r)?,
PropertyValue::UInt(u) => write_unsigned_integer(writer, *u)?,
PropertyValue::SInt(s) => write_signed_integer(writer, *s)?,
PropertyValue::AString(s) => write_ascii_string(writer, s.as_ref())?,
PropertyValue::BString(s) => write_byte_string(writer, s.as_ref())?,
PropertyValue::NString(s) => write_name_string(writer, s.as_ref())?,
PropertyValue::AStringRef(u) | PropertyValue::BStringRef(u) | PropertyValue::NStringRef(u)
=> write_unsigned_integer(writer, *u)?
};
Ok(())
}