diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index a211306..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "klamath_rs_ext" -version = "0.2.0" -authors = ["jan "] -edition = "2021" - - -[lib] -name = "klamath_rs_ext" -crate-type = ["cdylib", "rlib"] - - -[dependencies] -byteorder = "^1" diff --git a/klamath_rs_ext/__init__.py b/klamath_rs_ext/__init__.py deleted file mode 100644 index d042d92..0000000 --- a/klamath_rs_ext/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .basic import pack_int2 as pack_int2 -from .basic import pack_int4 as pack_int4 - - -__version__ = 0.2 - diff --git a/klamath_rs_ext/basic.py b/klamath_rs_ext/basic.py deleted file mode 100644 index aabc246..0000000 --- a/klamath_rs_ext/basic.py +++ /dev/null @@ -1,92 +0,0 @@ -from collections.abc import Sequence -import ctypes -from pathlib import Path -from itertools import chain - -import numpy -from numpy.typing import NDArray - -from .klamath_rs_ext import lib, ffi - - -CONV_TABLE_i16 = { - numpy.float64: lib.f64_to_i16, - numpy.float32: lib.f32_to_i16, - numpy.int64: lib.i64_to_i16, - numpy.int32: lib.i32_to_i16, - numpy.int16: lib.i16_to_i16, - numpy.uint64: lib.u64_to_i16, - numpy.uint32: lib.u32_to_i16, - numpy.uint16: lib.u16_to_i16, - } - -CONV_TABLE_i32 = { - numpy.float64: lib.f64_to_i32, - numpy.float32: lib.f32_to_i32, - numpy.int64: lib.i64_to_i32, - numpy.int32: lib.i32_to_i32, - numpy.uint64: lib.u64_to_i32, - numpy.uint32: lib.u32_to_i32, - } - - - -def pack_int2(data: NDArray[numpy.integer] | Sequence[int] | int) -> bytes: - arr = numpy.atleast_1d(data) - - for dtype in CONV_TABLE_i16.keys(): - if arr.dtype != dtype: - continue - - arr = numpy.require(arr, requirements=('C_CONTIGUOUS', 'ALIGNED', 'WRITEABLE', 'OWNDATA')) - if arr is data: - arr = numpy.array(arr, copy=True) - - fn = CONV_TABLE_i16[dtype] - buf = ffi.from_buffer(ffi.typeof(fn).args[0], arr, require_writable=True) - result = fn(buf, arr.size) - - if result != 0: - raise ValueError(f'Invalid value for conversion to Int2: {result}') - - i2arr = arr.view('>i2')[::arr.itemsize // 2] - return i2arr.tobytes() - - if arr.dtype == numpy.dtype('>i2'): - return arr.tobytes() - - if (arr > 32767).any() or (arr < -32768).any(): - raise Exception(f'int2 data out of range: {arr}') - - return arr.astype('>i2').tobytes() - - -def pack_int4(data: NDArray[numpy.integer] | Sequence[int] | int) -> bytes: - arr = numpy.atleast_1d(data) - - for dtype in CONV_TABLE_i32.keys(): - if arr.dtype != dtype: - continue - - arr = numpy.require(arr, requirements=('C_CONTIGUOUS', 'ALIGNED', 'WRITEABLE', 'OWNDATA')) - if arr is data: - arr = numpy.array(arr, copy=True) - - fn = CONV_TABLE_i32[dtype] - buf = ffi.from_buffer(ffi.typeof(fn).args[0], arr, require_writable=True) - result = fn(buf, arr.size) - - if result != 0: - raise ValueError(f'Invalid value for conversion to Int4: {result}') - - i4arr = arr.view('>i4')[::arr.itemsize // 4] - return i4arr.tobytes() - - if arr.dtype == numpy.dtype('>i4'): - return arr.tobytes() - - if (arr > 2147483647).any() or (arr < -2147483648).any(): - raise Exception(f'int4 data out of range: {arr}') - - return arr.astype('>i4').tobytes() - diff --git a/klamath_rs_ext/py.typed b/klamath_rs_ext/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 06aa1af..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,37 +0,0 @@ -[build-system] -requires = ["maturin>1.0,<2.0"] -build-backend = "maturin" - -[project] -name = "klamath_rs_ext" -description = "Compiled extensions for klamath GDS library" -#readme = "README.md" -#license = { file = "LICENSE.md" } -authors = [ - { name="Jan Petykiewicz", email="jan@mpxd.net" }, - ] -homepage = "https://mpxd.net/code/jan/klamath-rs" -repository = "https://mpxd.net/code/jan/klamath-rs" -classifiers = [ - "Programming Language :: Python :: 3", - "Development Status :: 4 - Beta", -# "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Intended Audience :: Information Technology", - "Intended Audience :: Manufacturing", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", - ] -requires-python = ">=3.11" -#include = [ -# "LICENSE.md" -# ] -dynamic = ["version"] -dependencies = [ - "cffi", - ] - -[tool.maturin] -bindings = "cffi" - diff --git a/src/basic.rs b/src/basic.rs deleted file mode 100644 index 1019be1..0000000 --- a/src/basic.rs +++ /dev/null @@ -1,393 +0,0 @@ -/// -/// Functionality for parsing and writing basic data types -/// -use byteorder::{ByteOrder, BigEndian}; -use std::io; -use std::fmt; - -pub type OResult = Result; - -pub type IResult<'a, O> = Result<(&'a [u8], O), (&'a [u8], ErrType)>; - -#[derive(Debug)] -pub enum ErrType { - Incomplete(Option), - Failed(String), -} - -pub fn fail(input: &[u8], msg: String) -> IResult { - Err((input, ErrType::Failed(msg))) -} - -pub fn incomplete(input: &[u8], size: Option) -> IResult { - Err((input, ErrType::Incomplete(size))) -} - -pub fn take_bytes>(input: &[u8], count: CC) -> IResult<&[u8]> { - let cc = count.into(); - if input.len() < cc { - incomplete(input, Some(cc)) - } else { - let (taken, input) = input.split_at(cc); - Ok((input, taken)) - } -} - - -/* - * Parse functions - */ -pub fn parse_u16(input: &[u8]) -> IResult { - let (input, buf) = take_bytes(input, 2_usize)?; - let val = BigEndian::read_u16(&buf); - Ok((input, val)) -} - -pub fn parse_int2(input: &[u8]) -> IResult { - let (input, buf) = take_bytes(input, 2_usize)?; - let val = BigEndian::read_i16(&buf); - Ok((input, val)) -} - -pub fn parse_int4(input: &[u8]) -> IResult { - let (input, buf) = take_bytes(input, 4_usize)?; - let val = BigEndian::read_i32(&buf); - Ok((input, val)) -} - -/// Convert GDS REAL8 to IEEE float64 -pub fn decode_real8(int: u64) -> f64 { - let neg = int & 0x8000_0000_0000_0000; - let exp = (int >> 56) & 0x7f; - let mut mant = (int & 0x00ff_ffff_ffff_ffff) as f64; - if neg != 0 { - mant *= -1.0 - } - let exp2 = 4 * (exp as i32 - 64) - 56; - mant * 2_f64.powi(exp2) -} - -pub fn parse_real8(input: &[u8]) -> IResult { - let (input, buf) = take_bytes(input, 8_usize)?; - let data = BigEndian::read_u64(&buf); - Ok((input, decode_real8(data))) -} - - -pub fn parse_datetime(input: &[u8]) -> IResult<[i16; 6]> { - let mut buf = [0_i16; 6]; - let mut input = input; - for ii in 0..6 { - (input, buf[ii]) = parse_int2(input)?; - } - buf[0] += 1900; // Year is from 1900 - Ok((input, buf)) -} - - -pub fn parse_bitarray(input: &[u8]) -> IResult<[bool; 16]> { - let mut bits = [false; 16]; - let (input, val) = parse_int2(input)?; - for ii in 0..16 { - bits[ii] = ((val >> (16 - 1 - ii)) & 0x01) == 1; - } - Ok((input, bits)) -} - - -pub fn parse_ascii(input: &[u8], length: u16) -> IResult> { - let length = length as usize; - let (input, data) = take_bytes(input, length)?; - let last = data[length - 1]; - let true_length = if last == 0 { length - 1 } else { length }; - let vec = data[..true_length].to_vec(); - Ok((input, vec)) -} - - -/* - * Pack functions - */ - -pub fn bitarray2int(bits: &[bool; 16]) -> u16 { - let mut int: u16 = 0; - for ii in 0..16 { - int |= (bits[ii] as u16) << (16 - 1 - ii); - } - int -} - -pub fn pack_bitarray(buf: &mut [u8], bits: &[bool; 16]) { - BigEndian::write_u16(buf, bitarray2int(bits)); -} - - -pub fn pack_int2(buf: &mut [u8], int: i16) { - BigEndian::write_i16(buf, int); -} - -pub fn pack_int4(buf: &mut [u8], int: i32) { - BigEndian::write_i32(buf, int); -} - -pub fn pack_real8(buf: &mut [u8], fnum: f64) -> Result<(), FloatTooBigError> { - BigEndian::write_u64(buf, encode_real8(fnum)?); - Ok(()) -} - -pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize { - let len = data.len(); - buf[..len].copy_from_slice(data); - if len % 2 == 1 { - buf[len] = 0; - len + 1 - } else { - len - } -} - - -pub fn pack_datetime(buf: &mut [u8], date: &[i16; 6]) { - assert!(buf.len() >= 6 * 2); - let year = date[0] - 1900; - pack_int2(buf, year); - for ii in 1..6 { - pack_int2(&mut buf[(2 * ii)..], date[ii]); - } -} - - -#[derive(Debug, Clone)] -pub struct FloatTooBigError { - float_value: f64, -} -impl fmt::Display for FloatTooBigError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Float {0} is too large for Real8", self.float_value) - } -} - -/// Convert from float64 to GDS REAL8 representation. -pub fn encode_real8(fnum: f64) -> Result { - // Split the ieee float bitfields - let ieee = fnum.to_bits(); - let sign = ieee & 0x8000_0000_0000_0000; - let ieee_exp = (ieee >> 52) as i32 & 0x7ff; - let ieee_mant = ieee & 0x000f_ffff_ffff_ffff; - - let subnorm = (ieee_exp == 0) & (ieee_mant != 0); - if (ieee_exp == 0) & (ieee_mant == 0) { - return Ok(0) - } - - // IEEE normal double is (1 + ieee_mant / 2^52) * 2^(ieee_exp - 1023) - // IEEE subnormal double is (ieee_mant / 2^52) * 2^(-1022) - // GDS real8 is (gds_mant / 2^(7*8)) * 16^(gds_exp - 64) - // = (gds_mant / 2^56) * 2^(4 * gds_exp - 256) - - // Convert exponent. - let exp2 = if subnorm { -1022 } else {ieee_exp + 1 - 1023}; // +1 is due to mantissa (1.xxxx in IEEE vs 0.xxxxx in GDSII) - let mut exp16 = exp2 / 4; - let rest = exp2 % 4; - - // Compensate for exponent coarseness - let comp = rest != 0; - let mut shift; - if comp { - exp16 += 1; - shift = 4 - rest; - } else { - shift = rest; - } - shift -= 3; // account for gds bit position - - // add leading one - let mut gds_mant_unshifted = ieee_mant; - if !subnorm { - gds_mant_unshifted += 0x10_0000_0000_0000; - } - - let mut gds_mant = if shift > 0 { - gds_mant_unshifted >> shift - } else { - gds_mant_unshifted << -shift - }; - - // add gds exponent bias - let mut gds_exp = exp16 + 64; - - if gds_exp < -14 { - // number is too small - return Ok(0) - } - - let neg_biased = gds_exp < 0; - if neg_biased { - gds_mant >>= gds_exp * 4; - gds_exp = 0; - } - - let too_big = (gds_exp > 0x7f) & !subnorm; - if too_big { - return Err(FloatTooBigError{float_value: fnum}); - } - - let gds_exp_bits = (gds_exp as u64) << 56; - - let real8 = sign | gds_exp_bits | gds_mant; - Ok(real8) -} - - - -#[cfg(test)] -mod tests { - #[test] - fn test_parse_bitarray() { - use crate::basic::parse_bitarray; - - //assert!(parse_bitarray(b"59") == 13625); - assert_eq!(parse_bitarray(b"\x00\x00").unwrap().1, [false; 16]); - assert_eq!(parse_bitarray(b"\xff\xff").unwrap().1, [true; 16]); - - let arr_0001 = parse_bitarray(b"\x00\x01").unwrap().1; - for (ii, &vv) in arr_0001.iter().enumerate() { - assert_eq!(ii == 15, vv); - } - - let arr_8000 = parse_bitarray(b"\x80\x00").unwrap().1; - for (ii, &vv) in arr_8000.iter().enumerate() { - assert_eq!(ii == 0, vv); - } - } - - #[test] - fn test_parse_int2() { - use crate::basic::parse_int2; - assert_eq!(parse_int2(b"59").unwrap().1, 13625); - assert_eq!(parse_int2(b"\0\0").unwrap().1, 0); - assert_eq!(parse_int2(b"\xff\xff").unwrap().1, -1); - } - - #[test] - fn test_parse_int4() { - use crate::basic::parse_int4; - assert_eq!(parse_int4(b"4321").unwrap().1, 875770417); - } - - #[test] - fn test_decode_real8() { - use crate::basic::decode_real8; - - // zeroes - assert_eq!(decode_real8(0x0), 0.0); - assert_eq!(decode_real8(1<<63), 0.0); // negative - assert_eq!(decode_real8(0xff << 56), 0.0); // denormalized - - assert_eq!(decode_real8(0x4110 << 48), 1.0); - assert_eq!(decode_real8(0xC120 << 48), -2.0); - } - - #[test] - #[should_panic] - fn test_encode_real8_panic() { - use crate::basic::encode_real8; - encode_real8(1e80).unwrap(); - } - - - #[test] - fn test_parse_real8() { - use crate::basic:: parse_real8; - - assert_eq!(0.0, parse_real8(&[0; 8]).unwrap().1); - assert_eq!(1.0, parse_real8(&[0x41, 0x10, 0, 0, 0, 0, 0, 0]).unwrap().1); - assert_eq!(-2.0, parse_real8(&[0xC1, 0x20, 0, 0, 0, 0, 0, 0]).unwrap().1); - } - - #[test] - fn test_parse_ascii() { - use crate::basic::parse_ascii; - - assert_eq!(parse_ascii(b"12345", 5).unwrap().1, b"12345"); - assert_eq!(parse_ascii(b"12345\0", 6).unwrap().1, b"12345"); // strips trailing null byte - assert_eq!(parse_ascii(b"123456", 6).unwrap().1, b"123456"); - } - - #[test] - fn test_pack_bitarray() { - use crate::basic::pack_bitarray; - let mut buf = [10; 3]; - let mut bools = [false; 16]; - bools[1] = true; - bools[2] = true; - bools[11] = true; - - pack_bitarray(&mut buf, &bools); - assert_eq!(buf[0], 0b0110_0000); - assert_eq!(buf[1], 0b0001_0000); - assert_eq!(buf[2], 10); - } - - #[test] - fn test_pack_int2() { - use crate::basic::pack_int2; - let mut buf = [10; 3 * 2]; - pack_int2(&mut buf, -3); - pack_int2(&mut buf[2..], 2); - pack_int2(&mut buf[4..], -1); - assert_eq!(buf[0..2], [0xFF, 0xFD]); - assert_eq!(buf[2..4], [0x00, 0x02]); - assert_eq!(buf[4..6], [0xFF, 0xFF]); - } - - #[test] - fn test_pack_int4() { - use crate::basic::pack_int4; - let mut buf = [10; 3 * 4]; - pack_int4(&mut buf, -3); - pack_int4(&mut buf[4..], 2); - pack_int4(&mut buf[8..], -1); - assert_eq!(buf[0..4], [0xFF, 0xFF, 0xFF, 0xFD]); - assert_eq!(buf[4..8], [0x00, 0x00, 0x00, 0x02]); - assert_eq!(buf[8..12], [0xFF, 0xFF, 0xFF, 0xFF]); - } - - #[test] - fn test_encode_real8() { - use crate::basic::{encode_real8, decode_real8}; - const REALS: [f64; 5] = [1.0, -2.0, 1e-9, 1e-3, 1e-12]; - for vv in REALS { - print!("{vv}\n"); - assert!((decode_real8(encode_real8(vv).unwrap()) - vv).abs() < f64::EPSILON); - } - } - - #[test] - fn test_pack_real8() { - use crate::basic::{pack_real8, parse_real8}; - const COUNT: usize = 7; - const REALS: [f64; COUNT] = [0.0, 1.0, -1.0, 0.5, 1e-9, 1e-3, 1e-12]; - let mut buf = [10; 8 * COUNT]; - for (ii, &vv) in REALS.iter().enumerate() { - pack_real8(&mut buf[ii * 8..], vv).unwrap(); - } - for (ii, &vv) in REALS.iter().enumerate() { - print!("{vv}\n"); - let parsed_val = parse_real8(&buf[ii * 8..]).unwrap().1; - assert!((parsed_val - vv).abs() < f64::EPSILON); - } - } - - #[test] - fn test_pack_ascii() { - use crate::basic::pack_ascii; - let mut buf = [10; 12]; - pack_ascii(&mut buf[0..], "4321".as_bytes()); - pack_ascii(&mut buf[6..], "321".as_bytes()); - assert_eq!(&buf[0..4], "4321".as_bytes()); - assert_eq!(&buf[4..6], [10, 10]); - assert_eq!(&buf[6..9], "321".as_bytes()); - assert_eq!(&buf[9..], [0, 10, 10]); - } -} diff --git a/src/elements.rs b/src/elements.rs deleted file mode 100644 index b711da2..0000000 --- a/src/elements.rs +++ /dev/null @@ -1,532 +0,0 @@ -/// -/// Functionality for reading/writing elements (geometry, text labels, -/// structure references) and associated properties. -/// - -use crate::records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF, - DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE, - LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING, - STRANS, MAG, ANGLE, PROPATTR, PROPVALUE, - ENDEL, BGNEXTN, ENDEXTN, SNAME, - }; - -use crate::records; -use crate::record::{RecordHeader, Record}; -use crate::basic::{OResult, IResult, fail}; - -use std::collections::HashMap; -use std::io::Write; - - -/// -/// Read element properties. -/// -/// Assumes PROPATTR records have unique values. -/// Stops reading after consuming ENDEL record. -/// -/// Args: -/// stream: Stream to read from. -/// -/// Returns: -/// propattr: -> propvalue mapping -/// -pub fn read_properties(input: &[u8]) -> IResult>> { - let mut properties = HashMap::new(); - - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != ENDEL::tag() { - if header.tag == PROPATTR::tag() { - let result = PROPATTR::read_data(input, header.data_size)?; - input = result.0; - let key = result.1; - let result = PROPVALUE::read(input)?; - input = result.0; - let value = result.1; - assert!(!properties.contains_key(&key), "Duplicate property key: {}", key); - properties.insert(key, value); - } - (input, header) = RecordHeader::read(input)?; - } - Ok((input, properties)) -} - - -/// -/// Write element properties. -/// -/// This is does _not_ write the ENDEL record. -/// -/// Args: -/// stream: Stream to write to. -/// -pub fn write_properties(ww: &mut W, properties: &HashMap::>) -> OResult { - let mut size = 0; - for (key, value) in properties { - size += PROPATTR::write(ww, key)?; - size += PROPVALUE::write(ww, value)?; - } - Ok(size) -} - -pub trait Element { - /// - /// Read from a stream to construct this object. - /// Consumes up to (and including) the ENDEL record. - /// - fn read(input: &[u8]) -> IResult where Self: Sized; - - /// - /// Write this element to a stream. - /// Finishes with an ENDEL record. - /// - fn write(&self, ww: &mut W) -> OResult; -} - -/// -/// Datastructure representing -/// an instance of a structure (SREF / structure reference) or -/// an array of instances (AREF / array reference). -/// Type is determined by the presence of the `colrow` tuple. -/// -/// Transforms are applied to each individual instance (_not_ -/// to the instance's origin location || array vectors). -/// -#[derive(Debug, Clone)] -pub struct Reference { - /// Name of the structure being referenced. - struct_name: Vec, - /// Whether to mirror the pattern (negate y-values / flip across x-axis). Default false. - invert_y: bool, - /// Scaling factor (default 1) - mag: f64, - /// Rotation (degrees counterclockwise) - angle_deg: f64, - - /// (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0). - /// (For AREF) 3 locations: - /// [`offset`, - /// `offset + col_basis_vector * colrow[0]`, - /// `offset + row_basis_vector * colrow[1]`] - /// which define the first instance's offset and the array's basis vectors. - /// Note that many GDS implementations only support manhattan basis vectors, and some - /// assume a certain axis mapping (e.g. x->columns, y->rows) and "reinterpret" the - /// basis vectors to match it. - xy: Vec, - - /// Number of columns and rows (AREF) || None (SREF) - colrow: Option<(i16, i16)>, - /// Properties associated with this reference. - properties: HashMap::>, -} - -impl Element for Reference { - fn read(input: &[u8]) -> IResult { - let mut invert_y = false; - let mut mag = 1.0; - let mut angle_deg = 0.0; - let mut colrow = None; - let (input, struct_name) = SNAME::skip_and_read(input)?; - - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != records::RTAG_XY { - match header.tag { - records::RTAG_STRANS => { - let result = STRANS::read_data(input, header.data_size)?; - input = result.0; - invert_y = result.1[0]; - }, - records::RTAG_MAG => - {(input, mag) = MAG::read_data(input, header.data_size)?;}, - records::RTAG_ANGLE => - {(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, - records::RTAG_COLROW => { - let result = COLROW::read_data(input, header.data_size)?; - input = result.0; - colrow = Some((result.1[0], result.1[1])); - }, - _ => - return fail(input, format!("Unexpected tag {:04x}", header.tag)), - }; - (input, header) = RecordHeader::read(input)?; - } - let (input, xy) = XY::read_data(input, header.data_size)?; - let (input, properties) = read_properties(input)?; - Ok((input, Reference{ - struct_name: struct_name, - xy: xy, - properties: properties, - colrow: colrow, - invert_y: invert_y, - mag: mag, - angle_deg: angle_deg - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += match self.colrow { - None => SREF::write(ww, &())?, - Some(_) => AREF::write(ww, &())?, - }; - - size += SNAME::write(ww, &self.struct_name)?; - if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y { - let strans = { - let mut arr = [false; 16]; - arr[0] = self.invert_y; - arr - }; - size += STRANS::write(ww, &strans)?; - if self.mag != 1.0 { - size += MAG::write(ww, &self.mag)?; - } - if self.angle_deg != 0.0 { - size += ANGLE::write(ww, &self.angle_deg)?; - } - } - - if let Some(cr) = self.colrow { - size += COLROW::write(ww, &vec!{cr.0, cr.1})?; - } - - size += XY::write(ww, &self.xy)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} - -impl Reference { - pub fn check(&self) { - if self.colrow.is_some() { - assert!(self.xy.len() != 6, "colrow is Some, so expected size-6 xy. Got {:?}", self.xy); - } else { - assert!(self.xy.len() != 2, "Expected size-2 xy. Got {:?}", self.xy); - } - } -} - - -/// -/// Datastructure representing a Boundary element. -/// -#[derive(Debug, Clone)] -pub struct Boundary { - /// (layer, data_type) tuple - layer: (i16, i16), - /// Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,... - xy: Vec, - /// Properties for the element. - properties: HashMap::>, -} - -impl Element for Boundary { - fn read(input: &[u8]) -> IResult { - let (input, layer) = LAYER::skip_and_read(input)?; - let (input, dtype) = DATATYPE::read(input)?; - let (input, xy) = XY::read(input)?; - let (input, properties) = read_properties(input)?; - Ok((input, Boundary{ - layer: (layer, dtype), - xy: xy, - properties: properties, - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += BOUNDARY::write(ww, &())?; - size += LAYER::write(ww, &self.layer.0)?; - size += DATATYPE::write(ww, &self.layer.1)?; - size += XY::write(ww, &self.xy)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} - - -/// -/// Datastructure representing a Path element. -/// -/// If `path_type < 4`, `extension` values are not written. -/// During read, `exension` defaults to (0, 0) even if unused. -/// -#[derive(Debug, Clone)] -pub struct Path { - /// (layer, data_type) tuple - layer: (i16, i16), - /// End-cap type (0: flush, 1: circle, 2: square, 4: custom) - path_type: i16, - /// Path width - width: i32, - /// Extension when using path_type=4. Ignored otherwise. - extension: (i32, i32), - /// Path centerline coordinates. [x0, y0, x1, y1,...] - xy: Vec, - /// Properties for the element. - properties: HashMap::>, -} - -impl Element for Path { - fn read(input: &[u8]) -> IResult { - let mut path_type = 0; - let mut width = 0; - let mut bgn_ext = 0; - let mut end_ext = 0; - let (input, layer) = LAYER::skip_and_read(input)?; - let (input, dtype) = DATATYPE::read(input)?; - - let (mut input, mut header) = RecordHeader::read(&input)?; - while header.tag != records::RTAG_XY { - match header.tag { - records::RTAG_PATHTYPE => - {(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, - records::RTAG_WIDTH => - {(input, width) = WIDTH::read_data(input, header.data_size)?;}, - records::RTAG_BGNEXTN => - {(input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;}, - records::RTAG_ENDEXTN => - {(input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;}, - _ => - return fail(input, format!("Unexpected tag {:04x}", header.tag)), - }; - (input, header) = RecordHeader::read(&input)?; - } - let (input, xy) = XY::read_data(input, header.data_size)?; - let (input, properties) = read_properties(input)?; - Ok((input, Path{ - layer: (layer, dtype), - xy: xy, - properties: properties, - extension: (bgn_ext, end_ext), - path_type: path_type, - width: width, - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += PATH::write(ww, &())?; - size += LAYER::write(ww, &self.layer.0)?; - size += DATATYPE::write(ww, &self.layer.1)?; - if self.path_type != 0 { - size += PATHTYPE::write(ww, &self.path_type)?; - } - if self.width != 0 { - size += WIDTH::write(ww, &self.width)?; - } - - if self.path_type < 4 { - let (bgn_ext, end_ext) = self.extension; - if bgn_ext != 0 { - size += BGNEXTN::write(ww, &bgn_ext)?; - } - if end_ext != 0 { - size += ENDEXTN::write(ww, &end_ext)?; - } - } - size += XY::write(ww, &self.xy)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} - - -/// -/// Datastructure representing a Box element. Rarely used. -/// -#[derive(Debug, Clone)] -pub struct GDSBox { - /// (layer, box_type) tuple - layer: (i16, i16), - /// Box coordinates (5 pairs) - xy: Vec, - /// Properties for the element. - properties: HashMap::>, -} - -impl Element for GDSBox { - fn read(input: &[u8]) -> IResult { - let (input, layer) = LAYER::skip_and_read(input)?; - let (input, dtype) = BOXTYPE::read(input)?; - let (input, xy) = XY::read(input)?; - let (input, properties) = read_properties(input)?; - Ok((input, GDSBox{ - layer: (layer, dtype), - xy: xy, - properties: properties, - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += BOX::write(ww, &())?; - size += LAYER::write(ww, &self.layer.0)?; - size += BOXTYPE::write(ww, &self.layer.1)?; - size += XY::write(ww, &self.xy)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} - - -/// -/// Datastructure representing a Node element. Rarely used. -/// -#[derive(Debug, Clone)] -pub struct Node { - /// (layer, box_type) tuple - layer: (i16, i16), - /// 1-50 pairs of coordinates. - xy: Vec, - /// Properties for the element. - properties: HashMap::>, -} - -impl Element for Node { - fn read(input: &[u8]) -> IResult { - let (input, layer) = LAYER::skip_and_read(input)?; - let (input, dtype) = NODETYPE::read(input)?; - let (input, xy) = XY::read(input)?; - let (input, properties) = read_properties(input)?; - Ok((input, Node{ - layer: (layer, dtype), - xy: xy, - properties: properties, - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += NODE::write(ww, &())?; - size += LAYER::write(ww, &self.layer.0)?; - size += NODETYPE::write(ww, &self.layer.1)?; - size += XY::write(ww, &self.xy)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} - -/// -/// Datastructure representing a text label. -/// -#[derive(Debug, Clone)] -pub struct Text { - /// (layer, node_type) tuple - layer: (i16, i16), - - /// Bit array. Default all zeros. - /// bits 0-1: 00 left/01 center/10 right - /// bits 2-3: 00 top/01 middle/10 bottom - /// bits 4-5: font number - presentation: [bool; 16], - - /// Default 0 - path_type: i16, - /// Default 0 - width: i32, - /// Vertical inversion. Default false. - invert_y: bool, - /// Scaling factor. Default 1. - mag: f64, - /// Rotation (ccw). Default 0. - angle_deg: f64, - /// Position (1 pair only) - xy: Vec, - /// Text content - string: Vec, - /// Properties for the element. - properties: HashMap::> -} - -impl Element for Text { - fn read(input: &[u8]) -> IResult { - let mut path_type = 0; - let mut presentation = [false; 16]; - let mut invert_y = false; - let mut width = 0; - let mut mag = 1.0; - let mut angle_deg = 0.0; - let (input, layer) = LAYER::skip_and_read(input)?; - let (input, dtype) = TEXTTYPE::read(input)?; - - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != records::RTAG_XY { - match header.tag { - records::RTAG_PRESENTATION => - {(input, presentation) = PRESENTATION::read_data(input, header.data_size)?;}, - records::RTAG_PATHTYPE => - {(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, - records::RTAG_WIDTH => - {(input, width) = WIDTH::read_data(input, header.data_size)?;}, - records::RTAG_STRANS => { - let result = STRANS::read_data(input, header.data_size)?; - input = result.0; - invert_y = result.1[0]; - }, - records::RTAG_MAG => - {(input, mag) = MAG::read_data(input, header.data_size)?;}, - records::RTAG_ANGLE => - {(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, - _ => - return fail(input, format!("Unexpected tag {:04x}", header.tag)), - } - (input, header) = RecordHeader::read(input)?; - } - let (input, xy) = XY::read_data(input, header.data_size)?; - - let (input, string) = STRING::read(input)?; - let (input, properties) = read_properties(input)?; - Ok((input, Text{ - layer: (layer, dtype), - xy: xy, - properties: properties, - string: string, - presentation: presentation, - path_type: path_type, - width: width, - invert_y: invert_y, - mag: mag, - angle_deg: angle_deg, - })) - } - - fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += TEXT::write(ww, &())?; - size += LAYER::write(ww, &self.layer.0)?; - size += TEXTTYPE::write(ww, &self.layer.1)?; - if self.presentation.iter().any(|&x| x) { - size += PRESENTATION::write(ww, &self.presentation)?; - } - if self.path_type != 0 { - size += PATHTYPE::write(ww, &self.path_type)?; - } - if self.width != 0 { - size += WIDTH::write(ww, &self.width)? - } - if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y { - let strans = { - let mut arr = [false; 16]; - arr[0] = self.invert_y; - arr - }; - size += STRANS::write(ww, &strans)?; - if self.mag != 1.0 { - size += MAG::write(ww, &self.mag)?; - } - if self.angle_deg != 0.0 { - size += ANGLE::write(ww, &self.angle_deg)?; - } - } - size += XY::write(ww, &self.xy)?; - size += STRING::write(ww, &self.string)?; - size += write_properties(ww, &self.properties)?; - size += ENDEL::write(ww, &())?; - Ok(size) - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index cf8365c..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,86 +0,0 @@ -extern crate byteorder; - -pub mod basic; -pub mod record; -pub mod records; -pub mod elements; -pub mod library; - - -use byteorder::{ByteOrder, BigEndian}; -use std::mem::size_of; - - -macro_rules! impl_i16be { - ( $tt:ty, $arr:ident, $size:ident ) => { - { - let sl = unsafe { std::slice::from_raw_parts_mut($arr, $size) }; - for xx in sl.iter_mut() { - if *xx < i16::MIN as $tt { return *xx } - if *xx > i16::MAX as $tt { return *xx } - - let mut buf = [0; size_of::<$tt>()]; - BigEndian::write_i16(&mut buf, *xx as i16); - *xx = <$tt>::from_le_bytes(buf); - } - 0 as $tt - } - } -} - - -macro_rules! impl_i32be { - ( $tt:ty, $arr:ident, $size:ident ) => { - { - let sl = unsafe { std::slice::from_raw_parts_mut($arr, $size) }; - for xx in sl.iter_mut() { - if *xx < i32::MIN as $tt { return *xx } - if *xx > i32::MAX as $tt { return *xx } - - let mut buf = [0; size_of::<$tt>()]; - BigEndian::write_i32(&mut buf, *xx as i32); - *xx = <$tt>::from_le_bytes(buf); - } - 0 as $tt - } - } -} - - -#[no_mangle] -pub extern "C" fn f64_to_i16(arr: *mut f64, size: usize) -> f64 { impl_i16be!(f64, arr, size) } -#[no_mangle] -pub extern "C" fn f64_to_i32(arr: *mut f64, size: usize) -> f64 { impl_i32be!(f64, arr, size) } - -#[no_mangle] -pub extern "C" fn f32_to_i16(arr: *mut f32, size: usize) -> f32 { impl_i16be!(f32, arr, size) } -#[no_mangle] -pub extern "C" fn f32_to_i32(arr: *mut f32, size: usize) -> f32 { impl_i32be!(f32, arr, size) } - -#[no_mangle] -pub extern "C" fn u64_to_i16(arr: *mut u64, size: usize) -> u64 { impl_i16be!(u64, arr, size) } -#[no_mangle] -pub extern "C" fn u64_to_i32(arr: *mut u64, size: usize) -> u64 { impl_i32be!(u64, arr, size) } - -#[no_mangle] -pub extern "C" fn i64_to_i16(arr: *mut i64, size: usize) -> i64 { impl_i16be!(i64, arr, size) } -#[no_mangle] -pub extern "C" fn i64_to_i32(arr: *mut i64, size: usize) -> i64 { impl_i32be!(i64, arr, size) } - -#[no_mangle] -pub extern "C" fn u32_to_i16(arr: *mut u32, size: usize) -> u32 { impl_i16be!(u32, arr, size) } -#[no_mangle] -pub extern "C" fn u32_to_i32(arr: *mut u32, size: usize) -> u32 { impl_i32be!(u32, arr, size) } - -#[no_mangle] -pub extern "C" fn i32_to_i16(arr: *mut i32, size: usize) -> i32 { impl_i16be!(i32, arr, size) } -#[no_mangle] -pub extern "C" fn i32_to_i32(arr: *mut i32, size: usize) -> i32 { impl_i32be!(i32, arr, size) } - - -#[no_mangle] -pub extern "C" fn u16_to_i16(arr: *mut u16, size: usize) -> u16 { impl_i16be!(u16, arr, size) } - -#[no_mangle] -pub extern "C" fn i16_to_i16(arr: *mut i16, size: usize) -> i16 { impl_i16be!(i16, arr, size) } - diff --git a/src/library.rs b/src/library.rs deleted file mode 100644 index e5b5758..0000000 --- a/src/library.rs +++ /dev/null @@ -1,393 +0,0 @@ -/// -/// File-level read/write functionality. -/// - -use std::io::Write; -use std::collections::HashMap; - -pub use crate::record; -pub use crate::record::{RecordHeader, Record}; -pub use crate::records; -pub use crate::elements; -pub use crate::elements::{Element}; -pub use crate::basic::{IResult, OResult, take_bytes, fail}; - - -const DEFAULT_DATE: [i16; 6] = [1900, 0, 0, 0, 0, 0]; - - -/// -/// Representation of the GDS file header. -/// -/// File header records: HEADER BGNLIB LIBNAME UNITS -/// Optional records are ignored if present and never written. -/// -/// Version is written as `600`. -/// -#[derive(Debug, Clone)] -pub struct FileHeader { - /// Number of user units in one database unit - user_units_per_db_unit: f64, - /// Number of meters in one database unit - meters_per_db_unit: f64, - /// Last-modified time [y, m, d, h, m, s] - mod_time: [i16; 6], - /// Last-accessed time [y, m, d, h, m, s] - acc_time: [i16; 6], - /// Library name - name: Vec, -} - -impl FileHeader { - pub fn new(name: &[u8], meters_per_db_unit: f64, user_units_per_db_unit: f64) -> Self { - FileHeader{ - mod_time: [0, 1, 1, 0, 0, 0], - acc_time: [0, 1, 1, 0, 0, 0], - name: name.to_owned(), - user_units_per_db_unit: user_units_per_db_unit, - meters_per_db_unit: meters_per_db_unit, - } - } - - /// Read and construct a header from the provided input. - /// - /// Args: - /// input: Seekable input to read from - /// - /// Returns: - /// FileHeader object - /// - pub fn read(input: &[u8]) -> IResult { - let (input, _version) = records::HEADER::read(input)?; - let (input, [mod_time, acc_time]) = records::BGNLIB::read(input)?; - let (input, name) = records::LIBNAME::skip_and_read(input)?; - let (input, (uu, dbu)) = records::UNITS::skip_and_read(input)?; - - Ok((input, FileHeader{ - mod_time: mod_time, - acc_time: acc_time, - name: name, - user_units_per_db_unit: uu, - meters_per_db_unit: dbu, - })) - } - - /// Write the header to a input - /// - /// Args: - /// input: input to write to - /// - /// Returns: - /// number of bytes written - /// - pub fn write(&self, ww: &mut W) -> OResult { - let mut size = 0; - size += records::HEADER::write(ww, &600)?; - size += records::BGNLIB::write(ww, &[self.mod_time, self.acc_time])?; - size += records::LIBNAME::write(ww, &self.name)?; - size += records::UNITS::write(ww, &(self.user_units_per_db_unit, self.meters_per_db_unit))?; - Ok(size) - } -} - - -/// -/// Scan through a GDS file, building a table of -/// {b'structure_name': byte_offset}. -/// The intent of this function is to enable random access -/// and/or partial (structure-by-structure) reads. -/// -/// Args: -/// input: Seekable input to read from. Should be positioned -/// before the first structure record, but possibly -/// already past the file header. -/// -pub fn scan_structs(input: &[u8]) -> IResult, usize>> { - let input_size = input.len(); - let mut positions = HashMap::new(); - - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != records::RTAG_ENDLIB { - (input, _) = take_bytes(input, header.data_size)?; - if header.tag == records::RTAG_BGNSTR { - let name; - (input, name) = records::STRNAME::read(input)?; - if positions.contains_key(&name) { - return fail(input, format!("Duplicate structure name: {:?}", name)); - } - let position = input_size - input.len(); - positions.insert(name, position); - } - (input, header) = RecordHeader::read(input)?; - } - Ok((input, positions)) -} - - -#[derive(Debug, Clone)] -pub struct Cell { - name: Vec, - - boundaries: Vec, - paths: Vec, - nodes: Vec, - boxes: Vec, - texts: Vec, - refs: Vec, -} - -impl Cell { - /// Build an empty cell - pub fn new(name: Vec) -> Self { - Cell{ - name: name, - boundaries: Vec::new(), - paths: Vec::new(), - nodes: Vec::new(), - boxes: Vec::new(), - texts: Vec::new(), - refs: Vec::new(), - } - } - - /// Skip to the next structure and attempt to read it. - /// - /// Args: - /// input: Seekable input to read from. - /// - /// Returns: - /// (name, elements) if a structure was found. - /// None if no structure was found before the end of the library. - /// - pub fn read(input: &[u8]) -> IResult> { - let (input, success) = records::BGNSTR::skip_past(input)?; - if !success { - return Ok((input, None)) - } - - let (input, name) = records::STRNAME::read(input)?; - let mut cell = Cell::new(name); - let (input, _) = cell.read_elements(input)?; - Ok((input, Some(cell))) - } - - /// Read elements from the input until an ENDSTR - /// record is encountered. The ENDSTR record is also - /// consumed. - /// - /// Args: - /// input: Seekable input to read from. - /// - /// Returns: - /// List of element objects. - /// - pub fn read_elements<'a>(&mut self, input: &'a [u8]) -> IResult<'a, ()> { - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != records::RTAG_ENDSTR { - match header.tag { - records::RTAG_BOUNDARY => { - let boundary; - (input, _) = records::BOUNDARY::read(input)?; - (input, boundary) = elements::Boundary::read(input)?; - self.boundaries.push(boundary); - }, - records::RTAG_PATH => { - let path; - (input, _) = records::PATH::read(input)?; - (input, path) = elements::Path::read(input)?; - self.paths.push(path); - }, - records::RTAG_NODE => { - let node; - (input, _) = records::NODE::read(input)?; - (input, node) = elements::Node::read(input)?; - self.nodes.push(node); - }, - records::RTAG_BOX => { - let gds_box; - (input, _) = records::BOX::read(input)?; - (input, gds_box) = elements::GDSBox::read(input)?; - self.boxes.push(gds_box); - }, - records::RTAG_TEXT => { - let txt; - (input, _) = records::TEXT::read(input)?; - (input, txt) = elements::Text::read(input)?; - self.texts.push(txt); - }, - records::RTAG_SREF => { - let sref; - (input, _) = records::SREF::read(input)?; - (input, sref) = elements::Reference::read(input)?; - self.refs.push(sref); - }, - records::RTAG_AREF => { - let aref; - (input, _) = records::AREF::read(input)?; - (input, aref) = elements::Reference::read(input)?; - self.refs.push(aref); - }, - _ => { - // don't care, skip - (input, _) = take_bytes(input, header.data_size)?; - } - } - (input, header) = RecordHeader::read(input)?; - } - Ok((input, ())) - } - - /// - /// Write a structure to the provided input. - /// - /// Args: - /// name: Structure name (ascii-encoded). - /// elements: List of Elements containing the geometry and text in this struct. - /// cre_time: Creation time (optional). - /// mod_time: Modification time (optional). - /// - /// Return: - /// Number of bytes written - /// - pub fn write( - &self, - ww: &mut W, - cre_time: Option<[i16; 6]>, - mod_time: Option<[i16; 6]>, - ) -> OResult { - let mut size = 0; - size += records::BGNSTR::write(ww, &[cre_time.unwrap_or(DEFAULT_DATE), - mod_time.unwrap_or(DEFAULT_DATE)])?; - size += records::STRNAME::write(ww, &self.name)?; - size += self.write_elements(ww)?; - size += records::ENDSTR::write(ww, &())?; - Ok(size) - } - - pub fn write_elements(&self, ww: &mut W) -> OResult { - let mut size = 0; - for boundary in &self.boundaries { - size += boundary.write(ww)?; - } - for path in &self.paths { - size += path.write(ww)?; - } - for node in &self.nodes { - size += node.write(ww)?; - } - for gds_box in &self.boxes { - size += gds_box.write(ww)?; - } - for text in &self.texts { - size += text.write(ww)?; - } - for reference in &self.refs { - size += reference.write(ww)?; - } - Ok(size) - } -} - - -/* -/// -/// Scan through a GDS file, building a table of instance counts -/// `{b'structure_name': {b'ref_name': count}}`. -/// -/// This is intended to provide a fast overview of the file's -/// contents without performing a full read of all elements. -/// -/// Args: -/// input: Seekable input to read from. Should be positioned -/// before the first structure record, but possibly -/// already past the file header. -/// -pub fn scan_hierarchy(input: &[u8]) -> IResult, HashMap::, u32>>> { - let mut structures = HashMap::new(); - - let mut ref_name = None; - let mut ref_count = None; - let (mut input, mut header) = RecordHeader::read(input)?; - let mut cur_structure = HashMap::new(); - while header.tag != records::RTAG_ENDLIB { - match header.tag { - records::RTAG_BGNSTR => { - (input, _) = take_bytes(input, header.data_size)?; - let result = records::STRNAME::read(input)?; - input = result.0; - let name = result.1; - if structures.contains_key(&name) { - return fail(input, format!("Duplicate structure name: {:?}", name)); - } - let mut cur_structure = HashMap::new(); - structures.insert(name, cur_structure); - ref_name = None; - ref_count = None; - }, - records::RTAG_SNAME => { - let result = records::SNAME::read_data(input, header.data_size)?; - input = result.0; - ref_name = Some(result.1); - }, - records::RTAG_COLROW => { - let result = records::COLROW::read_data(input, header.data_size)?; - input = result.0; - let (col, row) = (result.1[0], result.1[1]); - ref_count = Some((col * row) as u32); - }, - records::RTAG_ENDEL => { - *cur_structure.entry(ref_name.unwrap()).or_insert(0) += ref_count.unwrap_or(1); - }, - _ => { - (input, _) = take_bytes(input, header.data_size)?; - }, - } - (input, header) = RecordHeader::read(input)?; - } - Ok((input, structures)) -} -*/ - -/* -pub fn count_ref(input: &[u8]) -> IResult, u32))> { - let (input, found_struc) = records::BGNSTR.skip_past(input)?; - if !found_struc { - return Ok((input, None)) - } - let mut cur_structure = HashMap::new(); - let (input, name) = records::STRNAME::read(input)?; - if structures.contains_key(&name) { - return fail(input, format!("Duplicate structure name: {:?}", name)); - } - - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != records::RTAG_ENDSTR { - let mut ref_name = None; - let mut ref_count = None; - while header.tag != records::RTAG_ENDEL { - match header.tag { - records::RTAG_SNAME => { - let result = records::SNAME::read_data(input1, header.data_size)?; - input1 = result.0; - ref_name = Some(result.1); - }, - records::RTAG_COLROW => { - let result = records::COLROW::read_data(input1, header.data_size)?; - input1 = result.0; - let (col, row) = (result.1[0], result.1[1]); - ref_count = Some((col * row) as u32); - }, - _ => { - (input1, _) = take_bytes(input1, header.data_size)?; - }, - } - (input1, header) = RecordHeader::read(input1)?; - } - // got ENDEL, update count for this reference - *cur_structure.entry(ref_name.unwrap()).or_insert(0) += ref_count.unwrap_or(1); - (input1, header) = RecordHeader::read(input1)?; - } - structures.insert(name, cur_structure); - (input, header) = RecordHeader::read(input1)?; -} -*/ diff --git a/src/record.rs b/src/record.rs deleted file mode 100644 index 41921c4..0000000 --- a/src/record.rs +++ /dev/null @@ -1,393 +0,0 @@ -/// -/// Generic record-level read/write functionality. -/// -use std::io::Write; -use std::convert::TryInto; -use byteorder::{ByteOrder, BigEndian}; - - -use crate::basic::{pack_datetime, pack_bitarray, pack_ascii, pack_int2, pack_int4, pack_real8}; #[warn(unused_imports)] -use crate::basic::{parse_datetime, parse_bitarray, parse_ascii, parse_int2, parse_int4, parse_real8}; #[warn(unused_imports)] -use crate::basic::{OResult, IResult, fail, parse_u16, take_bytes}; -use crate::records; - - -//#[no_mangle] -//pub extern "C" fn write_record_header( - - -#[repr(C)] -pub struct RecordHeader { - pub tag: u16, - pub data_size: u16, -} - -impl RecordHeader { - pub fn read(input: &[u8]) -> IResult { - let (input, size) = parse_u16(input)?; - let (input, tag) = parse_u16(input)?; - Ok((input, RecordHeader{tag:tag, data_size:size - 4})) - } - - pub fn pack_into(&self) -> [u8; 4] { - assert!(self.data_size < 0xffff - 4, "Record too big!"); - let vals = [self.data_size, self.tag]; - let mut buf = [0x77; 4]; - BigEndian::write_u16_into(&vals, &mut buf); - buf - } - - pub fn write(&self, ww: &mut W) -> OResult { - let bytes = self.pack_into(); - ww.write(&bytes) - } -} - - -pub trait RecordData { - type BareData; - type InData : ?Sized; - type ByteData : AsRef<[u8]>; - - fn read(input: &[u8], size: u16) -> IResult; - fn pack_into(buf: &mut [u8], data: &Self::InData); - //fn size(data: &Self::BareData) -> u16; - fn pack(data: &Self::InData) -> Self::ByteData; -} - - -pub trait Record { - fn tag() -> u16; - fn expected_size() -> Option; - - fn check_size(actual_size: u16) -> Result<(), String> { - match Self::expected_size() { - Some(size) => if size == actual_size { - Ok(()) - } else { - Err(format!("Expected record size {}, got {}", size, actual_size)) - }, - None => Ok(()), - } - } - - fn read_header(input: &[u8]) -> IResult { - RecordHeader::read(input) - } - - fn write_header(ww: &mut W, data_size: u16) -> OResult { - RecordHeader{tag: Self::tag(), data_size: data_size}.write(ww) - } - - fn read_data(input: &[u8], size: u16) -> IResult { - RData::read(input, size) - } - - fn pack_data(buf: &mut [u8], data: &RData::InData) { - RData::pack_into(buf, data) - } - - /// - /// Skip to the end of the next occurence of this record. - /// - /// Return: - /// True if the record was encountered and skipped. - /// False if the end of the library was reached. - /// - fn skip_past(input: &[u8]) -> IResult { - let original_input = input; - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != Self::tag() { - (input, _) = take_bytes(input, header.data_size)?; - if header.tag == records::RTAG_ENDLIB { - return Ok((original_input, false)) - } - (input, header) = RecordHeader::read(input)?; - } - (input, _) = take_bytes(input, header.data_size)?; - Ok((input, true)) - } - - fn skip_and_read(input: &[u8]) -> IResult { - let (mut input, mut header) = RecordHeader::read(input)?; - while header.tag != Self::tag() { - (input, _) = take_bytes(input, header.data_size)?; - (input, header) = RecordHeader::read(input)?; - } - let (input, data) = Self::read_data(input, header.data_size)?; - Ok((input, data)) - } - - fn expect_header(input: &[u8]) -> IResult { - let (input, header) = RecordHeader::read(input)?; - if header.tag != Self::tag() { - fail(input, format!("Unexpected record! Got tag 0x{:04x}, expected 0x{:04x}", header.tag, Self::tag())) - } else { - Ok((input, header.data_size)) - } - } - - fn read(input: &[u8]) -> IResult { - let (input, size) = Self::expect_header(input)?; - Self::check_size(size).unwrap(); - let (input, data) = Self::read_data(input, size)?; - Ok((input, data)) - } - - fn write(ww: &mut W, data: &RData::InData) -> OResult { - let packed_data = RData::pack(data); - let data_bytes = packed_data.as_ref(); - let len: u16 = data_bytes.len().try_into().expect("Record longer than max size (u16)!"); - let mut size = 0; - size += Self::write_header(ww, len)?; - size += ww.write(data_bytes)?; - Ok(size) - } -} - -pub struct BitArray; -impl RecordData for BitArray { - type BareData = [bool; 16]; - type InData = [bool; 16]; - type ByteData = [u8; 2]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 2); - parse_bitarray(input) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_bitarray(buf, data); - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 2]; - Self::pack_into(&mut buf, data); - buf - } -} - - -pub struct Int2; -impl RecordData for Int2 { - type BareData = i16; - type InData = i16; - type ByteData = [u8; 2]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 2); - parse_int2(input) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_int2(buf, *data) - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 2]; - Self::pack_into(&mut buf, data); - buf - } -} - -pub struct Int4; -impl RecordData for Int4 { - type BareData = i32; - type InData = i32; - type ByteData = [u8; 4]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 4); - parse_int4(input) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_int4(buf, *data) - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 4]; - Self::pack_into(&mut buf, data); - buf - } -} - - -pub struct Int2Array; -impl RecordData for Int2Array { - type BareData = Vec; - type InData = [i16]; - type ByteData = Vec; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size % 2 == 0, "Record must contain an integer quantity of integers"); - let mut buf = Vec::with_capacity(size as usize / 2); - let mut input = input; - for ii in 0..buf.len() { - (input, buf[ii]) = parse_int2(input)?; - } - Ok((input, buf)) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - BigEndian::write_i16_into(&data, buf) - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = Vec::with_capacity(data.len() * 2); - Self::pack_into(&mut buf, data); - buf - } -} - -pub struct Int4Array; -impl RecordData for Int4Array { - type BareData = Vec; - type InData = [i32]; - type ByteData = Vec; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size % 4 == 0, "Record must contain an integer quantity of integers"); - let mut buf = Vec::with_capacity(size as usize / 4); - let mut input = input; - for ii in 0..buf.len() { - (input, buf[ii]) = parse_int4(input)?; - } - Ok((input, buf)) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - BigEndian::write_i32_into(&data, buf) - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = Vec::with_capacity(data.len() * 4); - Self::pack_into(&mut buf, data); - buf - } -} - -pub struct Real8; -impl RecordData for Real8 { - type BareData = f64; - type InData = f64; - type ByteData = [u8; 8]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 8); - parse_real8(input) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_real8(buf, *data).expect(&format!("Float {0} too big for Real8", data)) - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 8]; - Self::pack_into(&mut buf, data); - buf - } -} - -pub struct Real8Pair; -impl RecordData for Real8Pair { - type BareData = (f64, f64); - type InData = (f64, f64); - type ByteData = [u8; 2 * 8]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 2 * 8); - let (input, data0) = parse_real8(input)?; - let (input, data1) = parse_real8(input)?; - Ok((input, (data0, data1))) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_real8(&mut buf[8 * 0..], data.0).expect(&format!("Float.0 {0} too big for Real8", data.0)); - pack_real8(&mut buf[8 * 1..], data.1).expect(&format!("Float.1 {0} too big for Real8", data.1)); - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 2 * 8]; - Self::pack_into(&mut buf, data); - buf - } - - //fn write(ww: &mut W, data: &Self::BareData) -> OResult { - // let mut buf = [u8; 2 * 6 * 2]; - // Self::pack_into(&mut buf, data) - //} -} - -pub struct ASCII; -impl RecordData for ASCII { - type BareData = Vec; - type InData = [u8]; - type ByteData = Vec; - - fn read(input: &[u8], size: u16) -> IResult { - parse_ascii(input, size) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_ascii(buf, data); - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = Vec::with_capacity(data.len() * 4); - Self::pack_into(&mut buf, data); - buf - } -} - - -pub struct DateTimePair; -impl RecordData for DateTimePair { - type BareData = [[i16; 6]; 2]; - type InData = [[i16; 6]; 2]; - type ByteData = [u8; 2 * 6 * 2]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 2 * 6 * 2); - let (input, data0) = parse_datetime(input)?; - let (input, data1) = parse_datetime(input)?; - Ok((input, [data0, data1])) - } - - fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_datetime(&mut buf[6 * 2 * 0..], &data[0]); - pack_datetime(&mut buf[6 * 2 * 1..], &data[1]); - } - - fn pack(data: &Self::InData) -> Self::ByteData { - let mut buf = [0; 2 * 6 * 2]; - Self::pack_into(&mut buf, data); - buf - } - - //fn write(ww: &mut W, data: &Self::BareData) -> OResult { - // let mut buf = [u8; 2 * 6 * 2]; - // Self::pack_into(&mut buf, data) - //} -} - -pub struct Empty; -impl RecordData for Empty { - type BareData = (); - type InData = (); - type ByteData = [u8; 0]; - - fn read(input: &[u8], size: u16) -> IResult { - assert!(size == 0); - Ok((input, ())) - } - - fn pack_into(_buf: &mut [u8], _data: &Self::InData) { - } - - fn pack(_data: &Self::InData) -> Self::ByteData { - [] - } - //fn write(ww: &mut W, data: &Self::BareData) { - //} -} diff --git a/src/records.rs b/src/records.rs deleted file mode 100644 index 4fe21fa..0000000 --- a/src/records.rs +++ /dev/null @@ -1,547 +0,0 @@ -/// -/// Record type and tag definitions -/// - -use crate::record::{Record, Int2, Int4, Int2Array, Int4Array, Real8, Real8Pair, DateTimePair, BitArray, ASCII, Empty}; - -//use std::io::Write; - -// record tags -pub const RTAG_HEADER: u16 = 0x0002; -pub const RTAG_BGNLIB: u16 = 0x0102; -pub const RTAG_LIBNAME: u16 = 0x0206; -pub const RTAG_UNITS: u16 = 0x0305; // (user_units_per_db_unit, db_units_per_meter) -pub const RTAG_ENDLIB: u16 = 0x0400; -pub const RTAG_BGNSTR: u16 = 0x0502; -pub const RTAG_STRNAME: u16 = 0x0606; -pub const RTAG_ENDSTR: u16 = 0x0700; -pub const RTAG_BOUNDARY: u16 = 0x0800; -pub const RTAG_PATH: u16 = 0x0900; -pub const RTAG_SREF: u16 = 0x0a00; -pub const RTAG_AREF: u16 = 0x0b00; -pub const RTAG_TEXT: u16 = 0x0c00; -pub const RTAG_LAYER: u16 = 0x0d02; -pub const RTAG_DATATYPE: u16 = 0x0e02; -pub const RTAG_WIDTH: u16 = 0x0f03; -pub const RTAG_XY: u16 = 0x1003; -pub const RTAG_ENDEL: u16 = 0x1100; -pub const RTAG_SNAME: u16 = 0x1206; -pub const RTAG_COLROW: u16 = 0x1302; -pub const RTAG_NODE: u16 = 0x1500; -pub const RTAG_TEXTTYPE: u16 = 0x1602; -pub const RTAG_PRESENTATION: u16 = 0x1701; -pub const RTAG_SPACING: u16 = 0x1802; // unused; not sure about 02 -pub const RTAG_STRING: u16 = 0x1906; -pub const RTAG_STRANS: u16 = 0x1a01; -pub const RTAG_MAG: u16 = 0x1b05; -pub const RTAG_ANGLE: u16 = 0x1c05; -pub const RTAG_UINTEGER: u16 = 0x1d02; // unused; not sure about 02 -pub const RTAG_USTRING: u16 = 0x1e06; // unused; not sure about 06 -pub const RTAG_REFLIBS: u16 = 0x1f06; -pub const RTAG_FONTS: u16 = 0x2006; -pub const RTAG_PATHTYPE: u16 = 0x2102; -pub const RTAG_GENERATIONS: u16 = 0x2202; -pub const RTAG_ATTRTABLE: u16 = 0x2306; -pub const RTAG_STYPTABLE: u16 = 0x2406; // unused; not sure about 06 -pub const RTAG_STRTYPE: u16 = 0x2502; // unused -pub const RTAG_ELFLAGS: u16 = 0x2601; -pub const RTAG_ELKEY: u16 = 0x2703; // unused -pub const RTAG_LINKTYPE: u16 = 0x2803; // unused -pub const RTAG_LINKKEYS: u16 = 0x2903; // unused -pub const RTAG_NODETYPE: u16 = 0x2a02; -pub const RTAG_PROPATTR: u16 = 0x2b02; -pub const RTAG_PROPVALUE: u16 = 0x2c06; -pub const RTAG_BOX: u16 = 0x2d00; -pub const RTAG_BOXTYPE: u16 = 0x2e02; -pub const RTAG_PLEX: u16 = 0x2f03; -pub const RTAG_BGNEXTN: u16 = 0x3003; -pub const RTAG_ENDEXTN: u16 = 0x3103; -pub const RTAG_TAPENUM: u16 = 0x3202; -pub const RTAG_TAPECODE: u16 = 0x3302; -pub const RTAG_STRCLASS: u16 = 0x3401; -pub const RTAG_RESERVED: u16 = 0x3503; -pub const RTAG_FORMAT: u16 = 0x3602; -pub const RTAG_MASK: u16 = 0x3706; // list of Layers and dtypes -pub const RTAG_ENDMASKS: u16 = 0x3800; // end of MASKS records -pub const RTAG_LIBDIRSIZE: u16 = 0x3902; -pub const RTAG_SRFNAME: u16 = 0x3a06; -pub const RTAG_LIBSECUR: u16 = 0x3b02; -pub const RTAG_BORDER: u16 = 0x3c00; -pub const RTAG_SOFTFENCE: u16 = 0x3d00; -pub const RTAG_HARDFENCE: u16 = 0x3f00; -pub const RTAG_SOFTWIRE: u16 = 0x3f00; -pub const RTAG_HARDWIRE: u16 = 0x4000; -pub const RTAG_PATHPORT: u16 = 0x4100; -pub const RTAG_NODEPORT: u16 = 0x4200; -pub const RTAG_USERCONSTRAINT: u16 = 0x4300; -pub const RTAG_SPACERERROR: u16 = 0x4400; -pub const RTAG_CONTACT: u16 = 0x4500; - -/* -// data types -pub const DATA_TYPE_NONE: u16 = 0x00; -pub const DATA_TYPE_BIT: u16 = 0x01; -pub const DATA_TYPE_INT16: u16 = 0x02; -pub const DATA_TYPE_INT32: u16 = 0x03; -pub const DATA_TYPE_REAL32: u16 = 0x04; -pub const DATA_TYPE_REAL64: u16 = 0x05; -pub const DATA_TYPE_STR: u16 = 0x06; - -pub const MAX_DATA_SIZE: usize = 8; - -/// Returns the size of the given data type in bytes. -pub fn data_size(t: u16) -> Option { - match t { - x if x == DATA_TYPE_NONE => 0, - x if x == DATA_TYPE_BIT => 2, - x if x == DATA_TYPE_INT16 => 2, - x if x == DATA_TYPE_INT32 => 4, - x if x == DATA_TYPE_REAL32 => 4, - x if x == DATA_TYPE_REAL64 => 8, - _ => 0 - } -*/ - -pub struct HEADER; -impl Record for HEADER { - fn tag() -> u16 { RTAG_HEADER } - fn expected_size() -> Option { Some(2) } -} -//impl Record for HEADER; - -pub struct BGNLIB; -impl Record for BGNLIB { - fn tag() -> u16 { RTAG_BGNLIB } - fn expected_size() -> Option { Some(2 * 6) } -} - -pub struct LIBNAME; -impl Record for LIBNAME { - fn tag() -> u16 { RTAG_LIBNAME } - fn expected_size() -> Option { None } -} - -pub struct UNITS; -impl Record for UNITS { - // (user_units_per_db_unit, db_units_per_meter) - fn tag() -> u16 { RTAG_UNITS } - fn expected_size() -> Option { Some(2 * 8) } -} - -pub struct ENDLIB; -impl Record for ENDLIB { - fn tag() -> u16 { RTAG_ENDLIB } - fn expected_size() -> Option { Some(0) } -} - -pub struct BGNSTR; -impl Record for BGNSTR { - fn tag() -> u16 { RTAG_BGNSTR } - fn expected_size() -> Option { Some(2 * 6) } -} - -pub struct STRNAME; -impl Record for STRNAME { - fn tag() -> u16 { RTAG_STRNAME } - fn expected_size() -> Option { Some(2 * 6) } -} - -pub struct ENDSTR; -impl Record for ENDSTR { - fn tag() -> u16 { RTAG_ENDSTR } - fn expected_size() -> Option { Some(0) } -} - -pub struct BOUNDARY; -impl Record for BOUNDARY { - fn tag() -> u16 { RTAG_BOUNDARY } - fn expected_size() -> Option { Some(0) } -} - -pub struct PATH; -impl Record for PATH { - fn tag() -> u16 { RTAG_PATH } - fn expected_size() -> Option { Some(0) } -} - -pub struct SREF; -impl Record for SREF { - fn tag() -> u16 { RTAG_SREF } - fn expected_size() -> Option { Some(0) } -} - -pub struct AREF; -impl Record for AREF { - fn tag() -> u16 { RTAG_AREF } - fn expected_size() -> Option { Some(0) } -} - -pub struct TEXT; -impl Record for TEXT { - fn tag() -> u16 { RTAG_TEXT } - fn expected_size() -> Option { Some(0) } -} - -pub struct LAYER; -impl Record for LAYER { - fn tag() -> u16 { RTAG_LAYER } - fn expected_size() -> Option { Some(2) } -} - -pub struct DATATYPE; -impl Record for DATATYPE { - fn tag() -> u16 { RTAG_DATATYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct WIDTH; -impl Record for WIDTH { - fn tag() -> u16 { RTAG_WIDTH } - fn expected_size() -> Option { Some(4) } -} - -pub struct XY; -impl Record for XY { - fn tag() -> u16 { RTAG_XY } - fn expected_size() -> Option { None } -} - -pub struct ENDEL; -impl Record for ENDEL { - fn tag() -> u16 { RTAG_ENDEL } - fn expected_size() -> Option { Some(0) } -} - -pub struct SNAME; -impl Record for SNAME { - fn tag() -> u16 { RTAG_SNAME } - fn expected_size() -> Option { None } -} - -pub struct COLROW; -impl Record for COLROW { - fn tag() -> u16 { RTAG_COLROW } - fn expected_size() -> Option { Some(4) } -} - -pub struct NODE; -impl Record for NODE { - fn tag() -> u16 { RTAG_NODE } - fn expected_size() -> Option { Some(0) } -} - -pub struct TEXTTYPE; -impl Record for TEXTTYPE { - fn tag() -> u16 { RTAG_TEXTTYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct PRESENTATION; -impl Record for PRESENTATION { - fn tag() -> u16 { RTAG_PRESENTATION } - fn expected_size() -> Option { Some(2) } -} - -pub struct SPACING; -impl Record for SPACING { - fn tag() -> u16 { RTAG_SPACING } - fn expected_size() -> Option { Some(2) } -} - -pub struct STRING; -impl Record for STRING { - fn tag() -> u16 { RTAG_STRING } - fn expected_size() -> Option { None } -} - -pub struct STRANS; -impl Record for STRANS { - fn tag() -> u16 { RTAG_STRANS } - fn expected_size() -> Option { Some(2) } -} - -pub struct MAG; -impl Record for MAG { - fn tag() -> u16 { RTAG_MAG } - fn expected_size() -> Option { Some(8) } -} - -pub struct ANGLE; -impl Record for ANGLE { - fn tag() -> u16 { RTAG_ANGLE } - fn expected_size() -> Option { Some(8) } -} - -pub struct UINTEGER; -impl Record for UINTEGER { - fn tag() -> u16 { RTAG_UINTEGER } - fn expected_size() -> Option { Some(2) } -} - -pub struct USTRING; -impl Record for USTRING { - fn tag() -> u16 { RTAG_USTRING } - fn expected_size() -> Option { None } -} - -pub struct REFLIBS; -impl Record for REFLIBS { - fn tag() -> u16 { RTAG_REFLIBS } - fn expected_size() -> Option { None } -} -impl REFLIBS { - pub fn check_size(actual_size: usize) -> Result<(), String> { - if actual_size % 44 == 0 { - Ok(()) - } else { - Err(format!("Expected record size divisible by 44, got {}", actual_size)) - } - } -} - -pub struct FONTS; -impl Record for FONTS { - fn tag() -> u16 { RTAG_FONTS } - fn expected_size() -> Option { None } -} -impl FONTS { - pub fn check_size(actual_size: usize) -> Result<(), String> { - if actual_size % 44 == 0 { - Ok(()) - } else { - Err(format!("Expected record size divisible by 44, got {}", actual_size)) - } - } -} - -pub struct PATHTYPE; -impl Record for PATHTYPE { - fn tag() -> u16 { RTAG_PATHTYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct GENERATIONS; -impl Record for GENERATIONS { - fn tag() -> u16 { RTAG_GENERATIONS } - fn expected_size() -> Option { Some(2) } -} - -pub struct ATTRTABLE; -impl Record for ATTRTABLE { - fn tag() -> u16 { RTAG_ATTRTABLE } - fn expected_size() -> Option { None } -} -impl ATTRTABLE { - pub fn check_size(actual_size: usize) -> Result<(), String> { - if actual_size % 44 == 0 { - Ok(()) - } else { - Err(format!("Expected record size divisible by 44, got {}", actual_size)) - } - } -} - -pub struct STYPTABLE; -impl Record for STYPTABLE { - fn tag() -> u16 { RTAG_STYPTABLE } - fn expected_size() -> Option { None } -} - -pub struct STRTYPE; -impl Record for STRTYPE { - fn tag() -> u16 { RTAG_STRTYPE } - fn expected_size() -> Option { None } -} - -pub struct ELFLAGS; -impl Record for ELFLAGS { - fn tag() -> u16 { RTAG_ELFLAGS } - fn expected_size() -> Option { Some(2) } -} - -pub struct ELKEY; -impl Record for ELKEY { - fn tag() -> u16 { RTAG_ELKEY } - fn expected_size() -> Option { Some(2) } -} - -pub struct LINKTYPE; -impl Record for LINKTYPE { - fn tag() -> u16 { RTAG_LINKTYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct LINKKEYS; -impl Record for LINKKEYS { - fn tag() -> u16 { RTAG_LINKKEYS } - fn expected_size() -> Option { Some(2) } -} - -pub struct NODETYPE; -impl Record for NODETYPE { - fn tag() -> u16 { RTAG_NODETYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct PROPATTR; -impl Record for PROPATTR { - fn tag() -> u16 { RTAG_PROPATTR } - fn expected_size() -> Option { Some(2) } -} - -pub struct PROPVALUE; -impl Record for PROPVALUE { - fn tag() -> u16 { RTAG_PROPVALUE } - fn expected_size() -> Option { Some(2) } -} - -pub struct BOX; -impl Record for BOX { - fn tag() -> u16 { RTAG_BOX } - fn expected_size() -> Option { Some(0) } -} - -pub struct BOXTYPE; -impl Record for BOXTYPE { - fn tag() -> u16 { RTAG_BOXTYPE } - fn expected_size() -> Option { Some(2) } -} - -pub struct PLEX; -impl Record for PLEX { - fn tag() -> u16 { RTAG_PLEX } - fn expected_size() -> Option { Some(4) } -} - -pub struct BGNEXTN; -impl Record for BGNEXTN { - fn tag() -> u16 { RTAG_BGNEXTN } - fn expected_size() -> Option { Some(4) } -} - -pub struct ENDEXTN; -impl Record for ENDEXTN { - fn tag() -> u16 { RTAG_ENDEXTN } - fn expected_size() -> Option { Some(4) } -} - -pub struct TAPENUM; -impl Record for TAPENUM { - fn tag() -> u16 { RTAG_TAPENUM } - fn expected_size() -> Option { Some(2) } -} - -pub struct TAPECODE; -impl Record for TAPECODE { - fn tag() -> u16 { RTAG_TAPECODE } - fn expected_size() -> Option { Some(2 * 6) } -} - -pub struct STRCLASS; -impl Record for STRCLASS { - fn tag() -> u16 { RTAG_STRCLASS } - fn expected_size() -> Option { Some(2) } -} - -pub struct RESERVED; -impl Record for RESERVED { - fn tag() -> u16 { RTAG_RESERVED } - fn expected_size() -> Option { Some(2) } -} - -pub struct FORMAT; -impl Record for FORMAT { - fn tag() -> u16 { RTAG_FORMAT } - fn expected_size() -> Option { Some(2) } -} - -pub struct MASK; -impl Record for MASK { - fn tag() -> u16 { RTAG_MASK } - fn expected_size() -> Option { None } -} - -/// End of MASKS records -pub struct ENDMASKS; -impl Record for ENDMASKS { - fn tag() -> u16 { RTAG_ENDMASKS } - fn expected_size() -> Option { Some(0) } -} - -pub struct LIBDIRSIZE; -impl Record for LIBDIRSIZE { - fn tag() -> u16 { RTAG_LIBDIRSIZE } - fn expected_size() -> Option { Some(2) } -} - -pub struct SRFNAME; -impl Record for SRFNAME { - fn tag() -> u16 { RTAG_SRFNAME } - fn expected_size() -> Option { None } -} - -pub struct LIBSECUR; -impl Record for LIBSECUR { - fn tag() -> u16 { RTAG_LIBSECUR } - fn expected_size() -> Option { Some(2) } -} - -pub struct BORDER; -impl Record for BORDER { - fn tag() -> u16 { RTAG_BORDER } - fn expected_size() -> Option { Some(0) } -} - -pub struct SOFTFENCE; -impl Record for SOFTFENCE { - fn tag() -> u16 { RTAG_SOFTFENCE } - fn expected_size() -> Option { Some(0) } -} - -pub struct HARDFENCE; -impl Record for HARDFENCE { - fn tag() -> u16 { RTAG_HARDFENCE } - fn expected_size() -> Option { Some(0) } -} - -pub struct SOFTWIRE; -impl Record for SOFTWIRE { - fn tag() -> u16 { RTAG_SOFTWIRE } - fn expected_size() -> Option { Some(0) } -} - -pub struct HARDWIRE; -impl Record for HARDWIRE { - fn tag() -> u16 { RTAG_HARDWIRE } - fn expected_size() -> Option { Some(0) } -} - -pub struct PATHPORT; -impl Record for PATHPORT { - fn tag() -> u16 { RTAG_PATHPORT } - fn expected_size() -> Option { Some(0) } -} - -pub struct NODEPORT; -impl Record for NODEPORT { - fn tag() -> u16 { RTAG_NODEPORT } - fn expected_size() -> Option { Some(0) } -} - -pub struct USERCONSTRAINT; -impl Record for USERCONSTRAINT { - fn tag() -> u16 { RTAG_USERCONSTRAINT } - fn expected_size() -> Option { Some(0) } -} - -pub struct SPACERERROR; -impl Record for SPACERERROR { - fn tag() -> u16 { RTAG_SPACERERROR } - fn expected_size() -> Option { Some(0) } -} - -pub struct CONTACT; -impl Record for CONTACT { - fn tag() -> u16 { RTAG_CONTACT } - fn expected_size() -> Option { Some(0) } -}