WIP on (no branch): 48db472 snapshot 2021-12-18 21:05:00.635887
This commit is contained in:
commit
07100dee8e
250
src/basic.rs
250
src/basic.rs
@ -1,80 +1,106 @@
|
|||||||
/*
|
///
|
||||||
* Functionality for parsing and writing basic data types
|
/// Functionality for parsing and writing basic data types
|
||||||
*/
|
///
|
||||||
use nom;
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
use nom::{IResult};
|
|
||||||
use byteorder::BigEndian;
|
|
||||||
//use std::io::Write;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
pub type OResult = Result<usize, io::Error>;
|
||||||
|
|
||||||
|
pub type IResult<'a, O> = Result<(&'a [u8], O), (&'a [u8], ErrType)>;
|
||||||
|
|
||||||
|
pub enum ErrType {
|
||||||
|
Incomplete(Option<usize>),
|
||||||
|
Failed(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn fail<O>(input: &[u8], msg: String) -> IResult<O> {
|
||||||
|
Err((input, ErrType::Failed(msg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn incomplete<O>(input: &[u8], size: Option<usize>) -> IResult<O> {
|
||||||
|
Err((input, ErrType::Incomplete(size)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_bytes<CC: Into<usize>>(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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type OWResult = Result<usize, io::Error>;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse functions
|
* Parse functions
|
||||||
*/
|
*/
|
||||||
//pub fn parse_byte_as_bits(input: &[u8]) -> IResult<&[u8], (u8, u8, u8, u8, u8, u8, u8, u8)> {
|
pub fn parse_u16(input: &[u8]) -> IResult<u16> {
|
||||||
// nom::bits::bits(nom::sequence::tuple((
|
let (input, buf) = take_bytes(input, 2_usize)?;
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
let val = BigEndian::read_u16(&buf);
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
Ok((input, val))
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// nom::bits::complete::take::<_, _, _, CustomError<_>>(1_usize),
|
|
||||||
// )))(input)
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_int2(input: &[u8]) -> IResult<&[u8], i16> {
|
|
||||||
nom::number::streaming::be_i16(input)?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_int4(input: &[u8]) -> IResult<&[u8], i32> {
|
pub fn parse_int2(input: &[u8]) -> IResult<i16> {
|
||||||
nom::number::streaming::be_i32(input)?
|
let (input, buf) = take_bytes(input, 2_usize)?;
|
||||||
|
let val = BigEndian::read_i16(&buf);
|
||||||
|
Ok((input, val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_int4(input: &[u8]) -> IResult<i32> {
|
||||||
|
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 {
|
pub fn decode_real8(int: u64) -> f64 {
|
||||||
// Convert GDS REAL8 to IEEE float64
|
|
||||||
let neg = int & 0x8000_0000_0000_0000;
|
let neg = int & 0x8000_0000_0000_0000;
|
||||||
let exp = (int >> 56) & 0x7f;
|
let exp = (int >> 56) & 0x7f;
|
||||||
let mut mant = (int & 0x00ff_ffff_ffff_ffff) as f64;
|
let mut mant = (int & 0x00ff_ffff_ffff_ffff) as f64;
|
||||||
if neg != 0 {
|
if neg != 0 {
|
||||||
mant *= -1
|
mant *= -1.0
|
||||||
}
|
}
|
||||||
mant * 2_f64.powi(4 * (exp - 64) - 56)
|
let exp2 = 4 * (exp as i32 - 64) - 56;
|
||||||
|
mant * 2_f64.powi(exp2)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_real8(input: &[u8]) -> IResult<&[u8], f64> {
|
pub fn parse_real8(input: &[u8]) -> IResult<f64> {
|
||||||
let data = nom::number::streaming::be_u64(input)?;
|
let (input, buf) = take_bytes(input, 8_usize)?;
|
||||||
IResult::Ok(decode_real8(data))
|
let data = BigEndian::read_u64(&buf);
|
||||||
|
Ok((input, decode_real8(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_datetime(input: &[u8]) -> IResult<&[u8], [u16; 6]> {
|
pub fn parse_datetime(input: &[u8]) -> IResult<[i16; 6]> {
|
||||||
let mut buf = [0_u16; 6];
|
let mut buf = [0_i16; 6];
|
||||||
let mut parts = nom::multi::fill(parse_int2, &mut buf)(input);
|
let mut input = input;
|
||||||
parts[0] += 1900; // Year is from 1900
|
for ii in 0..6 {
|
||||||
IResult::Ok(parts)
|
(input, buf[ii]) = parse_int2(input)?;
|
||||||
|
}
|
||||||
|
buf[0] += 1900; // Year is from 1900
|
||||||
|
Ok((input, buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_bitarray(input: &[u8]) -> IResult<&[u8], [bool; 16]> {
|
pub fn parse_bitarray(input: &[u8]) -> IResult<[bool; 16]> {
|
||||||
let bits = [false; 16];
|
let mut bits = [false; 16];
|
||||||
let (input, val) = parse_int2(input)?;
|
let (input, val) = parse_int2(input)?;
|
||||||
for ii in 0..16 {
|
for ii in 0..16 {
|
||||||
bits[ii] = ((val >> (16 - 1 - ii)) & 0x01) == 1;
|
bits[ii] = ((val >> (16 - 1 - ii)) & 0x01) == 1;
|
||||||
}
|
}
|
||||||
bits
|
Ok((input, bits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_ascii(input: &[u8], length: usize) -> IResult<&[u8], Vec<u8>> {
|
pub fn parse_ascii(input: &[u8], length: u16) -> IResult<Vec<u8>> {
|
||||||
let last = input[length - 1];
|
let length = length as usize;
|
||||||
let true_length = if last == '\0' { length - 1 } else { length };
|
let (input, data) = take_bytes(input, length)?;
|
||||||
let vec = input[..true_length].to_vec();
|
let last = data[length - 1];
|
||||||
IResult::Ok((input[length..], vec))
|
let true_length = if last == 0 { length - 1 } else { length };
|
||||||
|
let vec = data[..true_length].to_vec();
|
||||||
|
Ok((input, vec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +108,7 @@ pub fn parse_ascii(input: &[u8], length: usize) -> IResult<&[u8], Vec<u8>> {
|
|||||||
* Pack functions
|
* Pack functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn pack_bitarray(bits: &[bool; 16]) -> u16 {
|
pub fn bitarray2int(bits: &[bool; 16]) -> u16 {
|
||||||
let mut int: u16 = 0;
|
let mut int: u16 = 0;
|
||||||
for ii in 0..16 {
|
for ii in 0..16 {
|
||||||
int |= (bits[ii] as u16) << (16 - 1 - ii);
|
int |= (bits[ii] as u16) << (16 - 1 - ii);
|
||||||
@ -90,24 +116,28 @@ pub fn pack_bitarray(bits: &[bool; 16]) -> u16 {
|
|||||||
int
|
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) {
|
pub fn pack_int2(buf: &mut [u8], int: i16) {
|
||||||
BigEndian::write_i16(&mut buf, int)
|
BigEndian::write_i16(buf, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pack_int4(buf: &mut [u8], int: i32) {
|
pub fn pack_int4(buf: &mut [u8], int: i32) {
|
||||||
BigEndian::write_i32(&mut buf, int)
|
BigEndian::write_i32(buf, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pack_real8(buf: &mut [u8], fnum: f64) {
|
pub fn pack_real8(buf: &mut [u8], fnum: f64) {
|
||||||
BigEndian::write_u64(&mut buf, encode_real8(fnum))
|
BigEndian::write_u64(buf, encode_real8(fnum))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize {
|
pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize {
|
||||||
let len = data.len();
|
let len = data.len();
|
||||||
buf[..len].copy_from_slice(data);
|
buf[..len].copy_from_slice(data);
|
||||||
if len % 2 == 1 {
|
if len % 2 == 1 {
|
||||||
buf[len] = '\0';
|
buf[len] = 0;
|
||||||
len + 1
|
len + 1
|
||||||
} else {
|
} else {
|
||||||
len
|
len
|
||||||
@ -115,19 +145,18 @@ pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn pack_datetime(buf: &mut [u8], date: &[u16; 6]) {
|
pub fn pack_datetime(buf: &mut [u8], date: &[i16; 6]) {
|
||||||
assert!(buf.len() >= 6 * 2);
|
assert!(buf.len() >= 6 * 2);
|
||||||
let year = date[0] - 1900;
|
let year = date[0] - 1900;
|
||||||
pack_int2(&mut buf, year);
|
pack_int2(buf, year);
|
||||||
for ii in 1..6 {
|
for ii in 1..6 {
|
||||||
pack_int2(&mut buf[(2 * ii)..], date[ii]);
|
pack_int2(&mut buf[(2 * ii)..], date[ii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Convert from float64 to GDS REAL8 representation.
|
||||||
pub fn encode_real8(fnum: f64) -> u64 {
|
pub fn encode_real8(fnum: f64) -> u64 {
|
||||||
// Convert from float64 to GDS REAL8 representation.
|
|
||||||
|
|
||||||
// Split the ieee float bitfields
|
// Split the ieee float bitfields
|
||||||
let ieee = fnum.to_bits();
|
let ieee = fnum.to_bits();
|
||||||
let sign = ieee & 0x8000_0000_0000_0000;
|
let sign = ieee & 0x8000_0000_0000_0000;
|
||||||
@ -191,8 +220,119 @@ pub fn encode_real8(fnum: f64) -> u64 {
|
|||||||
panic!("Number too big for real8 format"); //TODO error handling
|
panic!("Number too big for real8 format"); //TODO error handling
|
||||||
}
|
}
|
||||||
|
|
||||||
let gds_exp_bits = gds_exp << 56;
|
let gds_exp_bits = (gds_exp as u64) << 56;
|
||||||
|
|
||||||
let real8 = sign | gds_exp_bits | gds_mant;
|
let real8 = sign | gds_exp_bits | gds_mant;
|
||||||
real8
|
real8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn test_parse_bitarray() {
|
||||||
|
use 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 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 basic::parse_int4;
|
||||||
|
assert_eq!(parse_int4(b"4321").unwrap().1, 875770417);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_real8() {
|
||||||
|
use 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);
|
||||||
|
|
||||||
|
//TODO panics on invalid?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_real8() {
|
||||||
|
use 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 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn test_pack_bitarray() {
|
||||||
|
packed = pack_bitarray(321)
|
||||||
|
assert_eq!(len(packed), 2);
|
||||||
|
assert_eq!(packed, struct.pack('>H', 321));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_pack_int2() {
|
||||||
|
packed = pack_int2((3, 2, 1))
|
||||||
|
assert(len(packed) == 3*2)
|
||||||
|
assert(packed == struct.pack('>3h', 3, 2, 1))
|
||||||
|
assert(pack_int2([-3, 2, -1]) == struct.pack('>3h', -3, 2, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_pack_int4() {
|
||||||
|
packed = pack_int4((3, 2, 1))
|
||||||
|
assert(len(packed) == 3*4)
|
||||||
|
assert(packed == struct.pack('>3l', 3, 2, 1))
|
||||||
|
assert(pack_int4([-3, 2, -1]) == struct.pack('>3l', -3, 2, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_encode_real8() {
|
||||||
|
assert(encode_real8(numpy.array([0.0])) == 0)
|
||||||
|
arr = numpy.array((1.0, -2.0, 1e-9, 1e-3, 1e-12))
|
||||||
|
assert_array_equal(decode_real8(encode_real8(arr)), arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_pack_real8() {
|
||||||
|
reals = (0, 1, -1, 0.5, 1e-9, 1e-3, 1e-12)
|
||||||
|
packed = pack_real8(reals)
|
||||||
|
assert(len(packed) == len(reals) * 8)
|
||||||
|
assert_array_equal(parse_real8(packed), reals)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_pack_ascii() {
|
||||||
|
assert(pack_ascii(b'4321') == b'4321')
|
||||||
|
assert(pack_ascii(b'321') == b'321\0')
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
553
src/elements.rs
553
src/elements.rs
@ -1,10 +1,8 @@
|
|||||||
/*
|
///
|
||||||
* Functionality for reading/writing elements (geometry, text labels,
|
/// Functionality for reading/writing elements (geometry, text labels,
|
||||||
* structure references) and associated properties.
|
/// structure references) and associated properties.
|
||||||
*/
|
///
|
||||||
|
|
||||||
//from .record import Record
|
|
||||||
//
|
|
||||||
use records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF,
|
use records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF,
|
||||||
DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE,
|
DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE,
|
||||||
LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING,
|
LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING,
|
||||||
@ -13,132 +11,147 @@ use records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF,
|
|||||||
};
|
};
|
||||||
|
|
||||||
use records;
|
use records;
|
||||||
use record::RecordHeader;
|
use record::{RecordHeader, Record};
|
||||||
use basic::{OWResult};
|
use basic::{OResult, IResult, fail};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use nom::IResult;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn read_properties(input: &[u8]) -> IResult<&[u8], HashMap::<i32, Vec<u8>>> {
|
///
|
||||||
/*
|
/// Read element properties.
|
||||||
* Read element properties.
|
///
|
||||||
*
|
/// Assumes PROPATTR records have unique values.
|
||||||
* Assumes PROPATTR records have unique values.
|
/// Stops reading after consuming ENDEL record.
|
||||||
* Stops reading after consuming ENDEL record.
|
///
|
||||||
*
|
/// Args:
|
||||||
* Args:
|
/// stream: Stream to read from.
|
||||||
* stream: Stream to read from.
|
///
|
||||||
*
|
/// Returns:
|
||||||
* Returns:
|
/// propattr: -> propvalue mapping
|
||||||
* propattr: -> propvalue mapping
|
///
|
||||||
*/
|
pub fn read_properties(input: &[u8]) -> IResult<HashMap::<i16, Vec<u8>>> {
|
||||||
let properties = HashMap{};
|
let mut properties = HashMap::new();
|
||||||
|
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
while header.tag != ENDEL::tag() {
|
while header.tag != ENDEL::tag() {
|
||||||
if header.tag == PROPATTR::tag() {
|
if header.tag == PROPATTR::tag() {
|
||||||
let (input, key) = PROPATTR::read_data(input, header.data_size)?;
|
let result = PROPATTR::read_data(input, header.data_size)?;
|
||||||
let (input, value) = PROPVALUE::read(input)?;
|
input = result.0;
|
||||||
assert!(!properties.contains_key(key), format!{"Duplicate property key: {}", key});
|
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);
|
properties.insert(key, value);
|
||||||
}
|
}
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
Ok((input, properties))
|
Ok((input, properties))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn write_properties<W: Write>(ww: W, properties: &HashMap::<i32, Vec<u8>>) -> OWResult {
|
///
|
||||||
/*
|
/// Write element properties.
|
||||||
* Write element properties.
|
///
|
||||||
*
|
/// This is does _not_ write the ENDEL record.
|
||||||
* This is does _not_ write the ENDEL record.
|
///
|
||||||
*
|
/// Args:
|
||||||
* Args:
|
/// stream: Stream to write to.
|
||||||
* stream: Stream to write to.
|
///
|
||||||
*/
|
pub fn write_properties<W: Write>(ww: &mut W, properties: &HashMap::<i16, Vec<u8>>) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for (key, value) in &properties {
|
for (key, value) in properties {
|
||||||
size += PROPATTR::write(ww, key)?;
|
size += PROPATTR::write(ww, key)?;
|
||||||
size += PROPVALUE::write(ww, value)?;
|
size += PROPVALUE::write(ww, value)?;
|
||||||
}
|
}
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Element {
|
pub trait Element {
|
||||||
fn parse(input: &[u8]) -> Self;
|
///
|
||||||
/*
|
/// Read from a stream to construct this object.
|
||||||
* Read from a stream to construct this object.
|
/// Consumes up to (and including) the ENDEL record.
|
||||||
* Consumes up to (and including) the ENDEL record.
|
///
|
||||||
*/
|
fn read(input: &[u8]) -> IResult<Self> where Self: Sized;
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult;
|
///
|
||||||
/*
|
/// Write this element to a stream.
|
||||||
* Write this element to a stream.
|
/// Finishes with an ENDEL record.
|
||||||
* Finishes with an ENDEL record.
|
///
|
||||||
*/
|
fn write<W: Write>(&self, ww: &mut W) -> OResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Reference {
|
///
|
||||||
/*
|
/// Datastructure representing
|
||||||
* Datastructure representing
|
/// an instance of a structure (SREF / structure reference) or
|
||||||
* an instance of a structure (SREF / structure reference) or
|
/// an array of instances (AREF / array reference).
|
||||||
* an array of instances (AREF / array reference).
|
/// Type is determined by the presence of the `colrow` tuple.
|
||||||
* Type is determined by the presence of the `colrow` tuple.
|
///
|
||||||
*
|
/// Transforms are applied to each individual instance (_not_
|
||||||
* Transforms are applied to each individual instance (_not_
|
/// to the instance's origin location || array vectors).
|
||||||
* to the instance's origin location || array vectors).
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
struct_name: Vec<u8>, // Name of the structure being referenced.
|
pub struct Reference {
|
||||||
invert_y: bool, // Whether to mirror the pattern (negate y-values / flip across x-axis). Default false.
|
/// Name of the structure being referenced.
|
||||||
mag: f64, // Scaling factor (default 1) """
|
struct_name: Vec<u8>,
|
||||||
angle_deg: f64, // Rotation (degrees counterclockwise)
|
/// Whether to mirror the pattern (negate y-values / flip across x-axis). Default false.
|
||||||
xy: Vec<i32>,
|
invert_y: bool,
|
||||||
/*
|
/// Scaling factor (default 1)
|
||||||
* (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0).
|
mag: f64,
|
||||||
* (For AREF) 3 locations:
|
/// Rotation (degrees counterclockwise)
|
||||||
* [`offset`,
|
angle_deg: f64,
|
||||||
* `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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
colrow: Option<(i32, i32)>, // Number of columns and rows (AREF) || None (SREF)
|
/// (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0).
|
||||||
properties: HashMap::<i16, Vec<u8>>, // Properties associated with this reference.
|
/// (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<i32>,
|
||||||
|
|
||||||
|
/// Number of columns and rows (AREF) || None (SREF)
|
||||||
|
colrow: Option<(i16, i16)>,
|
||||||
|
/// Properties associated with this reference.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Reference {
|
impl Element for Reference {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let mut invert_y = false;
|
let mut invert_y = false;
|
||||||
let mut mag = 1;
|
let mut mag = 1.0;
|
||||||
let mut angle_deg = 0;
|
let mut angle_deg = 0.0;
|
||||||
let mut colrow = None;
|
let mut colrow = None;
|
||||||
let (input, mut struct_name) = SNAME::skip_and_read(input)?;
|
let (input, struct_name) = SNAME::skip_and_read(input)?;
|
||||||
|
|
||||||
let (input, mut header) = RecordHeader::parse(input)?;
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
while header.tag != records::RTAG_XY {
|
while header.tag != records::RTAG_XY {
|
||||||
match header.tag {
|
match header.tag {
|
||||||
records::RTAG_STRANS =>
|
records::RTAG_STRANS => {
|
||||||
{let (input, invert_y) = STRANS::read_data(input, header.data_size)?[0];},
|
let result = STRANS::read_data(input, header.data_size)?;
|
||||||
|
input = result.0;
|
||||||
|
invert_y = result.1[0];
|
||||||
|
},
|
||||||
records::RTAG_MAG =>
|
records::RTAG_MAG =>
|
||||||
{let (input, mag) = MAG::read_data(input, header.data_size)?;},
|
{(input, mag) = MAG::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_ANGLE =>
|
records::RTAG_ANGLE =>
|
||||||
{let (input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
{(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_COLROW =>
|
records::RTAG_COLROW => {
|
||||||
{let (input, colrow) = COLROW::read_data(input, header.data_size)?;},
|
let result = COLROW::read_data(input, header.data_size)?;
|
||||||
|
input = result.0;
|
||||||
|
colrow = Some((result.1[0], result.1[1]));
|
||||||
|
},
|
||||||
_ =>
|
_ =>
|
||||||
return Err(format!("Unexpected tag {:04x}", header.tag)),
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
||||||
};
|
};
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
let (input, xy) = XY::read_data(input, header.data_size)?;
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
Reference{
|
Ok((input, Reference{
|
||||||
struct_name: struct_name,
|
struct_name: struct_name,
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
@ -146,34 +159,39 @@ impl Element for Reference {
|
|||||||
invert_y: invert_y,
|
invert_y: invert_y,
|
||||||
mag: mag,
|
mag: mag,
|
||||||
angle_deg: angle_deg
|
angle_deg: angle_deg
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += match self.colrow {
|
size += match self.colrow {
|
||||||
None => SREF::write(ww)?,
|
None => SREF::write(ww, &())?,
|
||||||
Some(_) => AREF::write(ww)?,
|
Some(_) => AREF::write(ww, &())?,
|
||||||
};
|
};
|
||||||
|
|
||||||
size += SNAME::write(ww, self.struct_name)?;
|
size += SNAME::write(ww, &self.struct_name)?;
|
||||||
if self.angle_deg != 0 || self.mag != 1 || self.invert_y {
|
if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y {
|
||||||
size += STRANS::write(ww, (self.invert_y as u16) << 15)?;
|
let strans = {
|
||||||
if self.mag != 1 {
|
let mut arr = [false; 16];
|
||||||
size += MAG::write(ww, self.mag)?;
|
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 {
|
if self.angle_deg != 0.0 {
|
||||||
size += ANGLE::write(ww, self.angle_deg)?;
|
size += ANGLE::write(ww, &self.angle_deg)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.colrow.is_some() {
|
if let Some(cr) = self.colrow {
|
||||||
size += COLROW::write(ww, self.colrow)?;
|
size += COLROW::write(ww, &vec!{cr.0, cr.1})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww, None)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,259 +199,289 @@ impl Element for Reference {
|
|||||||
impl Reference {
|
impl Reference {
|
||||||
pub fn check(&self) {
|
pub fn check(&self) {
|
||||||
if self.colrow.is_some() {
|
if self.colrow.is_some() {
|
||||||
assert!(self.xy.len() != 6, format!("colrow is Some, so expected size-6 xy. Got {}", self.xy));
|
assert!(self.xy.len() != 6, "colrow is Some, so expected size-6 xy. Got {:?}", self.xy);
|
||||||
} else {
|
} else {
|
||||||
assert!(self.xy.len() != 2, format!("Expected size-2 xy. Got {}", self.xy));
|
assert!(self.xy.len() != 2, "Expected size-2 xy. Got {:?}", self.xy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Boundary {
|
///
|
||||||
/*
|
/// Datastructure representing a Boundary element.
|
||||||
* Datastructure representing a Boundary element.
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
layer: (i16, i16), // (layer, data_type) tuple
|
pub struct Boundary {
|
||||||
xy: Vec<i32>, // Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,...
|
/// (layer, data_type) tuple
|
||||||
properties: HashMap::<i16, Vec<u8>>, // Properties for the element.
|
layer: (i16, i16),
|
||||||
|
/// Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,...
|
||||||
|
xy: Vec<i32>,
|
||||||
|
/// Properties for the element.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Boundary {
|
impl Element for Boundary {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let (input, layer) = LAYER::skip_and_read(input)?;
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
||||||
let (input, dtype) = DATATYPE::read(input)?;
|
let (input, dtype) = DATATYPE::read(input)?;
|
||||||
let (input, xy) = XY::read(input)?;
|
let (input, xy) = XY::read(input)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
Boundary{
|
Ok((input, Boundary{
|
||||||
layer: (layer, dtype),
|
layer: (layer, dtype),
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += BOUNDARY::write(ww)?;
|
size += BOUNDARY::write(ww, &())?;
|
||||||
size += LAYER::write(ww, self.layer.0)?;
|
size += LAYER::write(ww, &self.layer.0)?;
|
||||||
size += DATATYPE::write(ww, self.layer.1)?;
|
size += DATATYPE::write(ww, &self.layer.1)?;
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Path {
|
///
|
||||||
/*
|
/// Datastructure representing a Path element.
|
||||||
* Datastructure representing a Path element.
|
///
|
||||||
|
/// If `path_type < 4`, `extension` values are not written.
|
||||||
* If `path_type < 4`, `extension` values are not written.
|
/// During read, `exension` defaults to (0, 0) even if unused.
|
||||||
* During read, `exension` defaults to (0, 0) even if unused.
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
layer: (i16, i16), // (layer, data_type) tuple
|
pub struct Path {
|
||||||
path_type: i16, // End-cap type (0: flush, 1: circle, 2: square, 4: custom)
|
/// (layer, data_type) tuple
|
||||||
width: i16, // Path width
|
layer: (i16, i16),
|
||||||
extension: (i32, i32), // Extension when using path_type=4. Ignored otherwise.
|
/// End-cap type (0: flush, 1: circle, 2: square, 4: custom)
|
||||||
xy: Vec<i32>, // Path centerline coordinates. [x0, y0, x1, y1,...]
|
path_type: i16,
|
||||||
properties: HashMap::<i16, Vec<u8>>, //Properties for the element.
|
/// Path width
|
||||||
|
width: i32,
|
||||||
|
/// Extension when using path_type=4. Ignored otherwise.
|
||||||
|
extension: (i32, i32),
|
||||||
|
/// Path centerline coordinates. [x0, y0, x1, y1,...]
|
||||||
|
xy: Vec<i32>,
|
||||||
|
/// Properties for the element.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Path {
|
impl Element for Path {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let mut path_type = 0;
|
let mut path_type = 0;
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
let mut bgn_ext = 0;
|
let mut bgn_ext = 0;
|
||||||
let mut end_ext = 0;
|
let mut end_ext = 0;
|
||||||
let (input, mut layer) = LAYER::skip_and_read(input)?;
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
||||||
let (input, mut dtype) = DATATYPE::read(input)?;
|
let (input, dtype) = DATATYPE::read(input)?;
|
||||||
|
|
||||||
let (input, mut header) = RecordHeader::parse(&input)?;
|
let (mut input, mut header) = RecordHeader::read(&input)?;
|
||||||
while header.tag != records::RTAG_XY {
|
while header.tag != records::RTAG_XY {
|
||||||
match header.tag {
|
match header.tag {
|
||||||
records::RTAG_PATHTYPE =>
|
records::RTAG_PATHTYPE =>
|
||||||
{let (input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
{(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_WIDTH =>
|
records::RTAG_WIDTH =>
|
||||||
{let (input, width) = WIDTH::read_data(input, header.data_size)?;},
|
{(input, width) = WIDTH::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_BGNEXTN =>
|
records::RTAG_BGNEXTN =>
|
||||||
{let (input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;},
|
{(input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_ENDEXTN =>
|
records::RTAG_ENDEXTN =>
|
||||||
{let (input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;},
|
{(input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;},
|
||||||
_ =>
|
_ =>
|
||||||
return Err(format!("Unexpected tag {:04x}", header.tag)),
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
||||||
};
|
};
|
||||||
let (input, header) = RecordHeader::parse(&input)?;
|
(input, header) = RecordHeader::read(&input)?;
|
||||||
}
|
}
|
||||||
let (input, xy) = XY::read_data(input, header.data_size)?;
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
Path{
|
Ok((input, Path{
|
||||||
layer: (layer, dtype),
|
layer: (layer, dtype),
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
extension: (bgn_ext, end_ext),
|
extension: (bgn_ext, end_ext),
|
||||||
path_type: path_type,
|
path_type: path_type,
|
||||||
width: width,
|
width: width,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += PATH::write(ww)?;
|
size += PATH::write(ww, &())?;
|
||||||
size += LAYER::write(ww, self.layer[0])?;
|
size += LAYER::write(ww, &self.layer.0)?;
|
||||||
size += DATATYPE::write(ww, self.layer[1])?;
|
size += DATATYPE::write(ww, &self.layer.1)?;
|
||||||
if self.path_type != 0 {
|
if self.path_type != 0 {
|
||||||
size += PATHTYPE::write(ww, self.path_type)?;
|
size += PATHTYPE::write(ww, &self.path_type)?;
|
||||||
}
|
}
|
||||||
if self.width != 0 {
|
if self.width != 0 {
|
||||||
size += WIDTH::write(ww, self.width)?;
|
size += WIDTH::write(ww, &self.width)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.path_type < 4 {
|
if self.path_type < 4 {
|
||||||
let (bgn_ext, end_ext) = self.extension;
|
let (bgn_ext, end_ext) = self.extension;
|
||||||
if bgn_ext != 0 {
|
if bgn_ext != 0 {
|
||||||
size += BGNEXTN::write(ww, bgn_ext)?;
|
size += BGNEXTN::write(ww, &bgn_ext)?;
|
||||||
}
|
}
|
||||||
if end_ext != 0 {
|
if end_ext != 0 {
|
||||||
size += ENDEXTN::write(ww, end_ext)?;
|
size += ENDEXTN::write(ww, &end_ext)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct GDSBox {
|
///
|
||||||
/*
|
/// Datastructure representing a Box element. Rarely used.
|
||||||
* Datastructure representing a Box element. Rarely used.
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
layer: (i16, i16), // (layer, box_type) tuple
|
pub struct GDSBox {
|
||||||
xy: Vec<i32>, // Box coordinates (5 pairs)
|
/// (layer, box_type) tuple
|
||||||
properties: HashMap::<i16, Vec<u8>>, // Properties for the element.
|
layer: (i16, i16),
|
||||||
|
/// Box coordinates (5 pairs)
|
||||||
|
xy: Vec<i32>,
|
||||||
|
/// Properties for the element.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for GDSBox {
|
impl Element for GDSBox {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let (input, layer) = LAYER::skip_and_read(input)?;
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
||||||
let (input, dtype) = BOXTYPE::read(input)?;
|
let (input, dtype) = BOXTYPE::read(input)?;
|
||||||
let (input, xy) = XY::read(input)?;
|
let (input, xy) = XY::read(input)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
GDSBox{
|
Ok((input, GDSBox{
|
||||||
layer: (layer, dtype),
|
layer: (layer, dtype),
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += BOX::write(ww)?;
|
size += BOX::write(ww, &())?;
|
||||||
size += LAYER::write(ww, self.layer[0])?;
|
size += LAYER::write(ww, &self.layer.0)?;
|
||||||
size += BOXTYPE::write(ww, self.layer[1])?;
|
size += BOXTYPE::write(ww, &self.layer.1)?;
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Node {
|
///
|
||||||
/*
|
/// Datastructure representing a Node element. Rarely used.
|
||||||
* Datastructure representing a Node element. Rarely used.
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
layer: (i16, i16), // (layer, box_type) tuple
|
pub struct Node {
|
||||||
xy: Vec<i32>, // 1-50 pairs of coordinates.
|
/// (layer, box_type) tuple
|
||||||
properties: HashMap::<i16, Vec<u8>>, // Properties for the element.
|
layer: (i16, i16),
|
||||||
|
/// 1-50 pairs of coordinates.
|
||||||
|
xy: Vec<i32>,
|
||||||
|
/// Properties for the element.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Node {
|
impl Element for Node {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let (input, layer) = LAYER::skip_and_read(input)?;
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
||||||
let (input, dtype) = NODETYPE::read(input)?;
|
let (input, dtype) = NODETYPE::read(input)?;
|
||||||
let (input, xy) = XY::read(input)?;
|
let (input, xy) = XY::read(input)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
Node{
|
Ok((input, Node{
|
||||||
layer: (layer, dtype),
|
layer: (layer, dtype),
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += NODE::write(ww)?;
|
size += NODE::write(ww, &())?;
|
||||||
size += LAYER::write(ww, self.layer[0])?;
|
size += LAYER::write(ww, &self.layer.0)?;
|
||||||
size += NODETYPE::write(ww, self.layer[1])?;
|
size += NODETYPE::write(ww, &self.layer.1)?;
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Text {
|
///
|
||||||
/*
|
/// Datastructure representing a text label.
|
||||||
* Datastructure representing a text label.
|
///
|
||||||
*/
|
#[derive(Debug, Clone)]
|
||||||
layer: (i16, i16), // (layer, node_type) tuple
|
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],
|
presentation: [bool; 16],
|
||||||
/*
|
|
||||||
* Bit array. Default all zeros.
|
/// Default 0
|
||||||
* bits 0-1: 00 left/01 center/10 right
|
path_type: i16,
|
||||||
* bits 2-3: 00 top/01 middle/10 bottom
|
/// Default 0
|
||||||
* bits 4-5: font number
|
width: i32,
|
||||||
*/
|
/// Vertical inversion. Default false.
|
||||||
path_type: i16, // Default 0
|
invert_y: bool,
|
||||||
width: i32, // Default 0
|
/// Scaling factor. Default 1.
|
||||||
invert_y: bool, // Vertical inversion. Default false.
|
mag: f64,
|
||||||
mag: f64, // Scaling factor. Default 1.
|
/// Rotation (ccw). Default 0.
|
||||||
angle_deg: f64, // Rotation (ccw). Default 0.
|
angle_deg: f64,
|
||||||
xy: Vec<i32>, // Position (1 pair only)
|
/// Position (1 pair only)
|
||||||
string: Vec<u8>, // Text content
|
xy: Vec<i32>,
|
||||||
properties: HashMap::<i16, Vec<u8>> // Properties for the element.
|
/// Text content
|
||||||
|
string: Vec<u8>,
|
||||||
|
/// Properties for the element.
|
||||||
|
properties: HashMap::<i16, Vec<u8>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Text {
|
impl Element for Text {
|
||||||
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
|
fn read(input: &[u8]) -> IResult<Self> {
|
||||||
let mut path_type = 0;
|
let mut path_type = 0;
|
||||||
let mut presentation = 0;
|
let mut presentation = [false; 16];
|
||||||
let mut invert_y = false;
|
let mut invert_y = false;
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
let mut mag = 1;
|
let mut mag = 1.0;
|
||||||
let mut angle_deg = 0;
|
let mut angle_deg = 0.0;
|
||||||
let (input, layer) = LAYER::skip_and_read(input)?;
|
let (input, layer) = LAYER::skip_and_read(input)?;
|
||||||
let (input, dtype) = TEXTTYPE::read(input)?;
|
let (input, dtype) = TEXTTYPE::read(input)?;
|
||||||
|
|
||||||
let mut header = RecordHeader::parse(input)?;
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
while header.tag != records::RTAG_XY {
|
while header.tag != records::RTAG_XY {
|
||||||
match header.tag {
|
match header.tag {
|
||||||
records::RTAG_PRESENTATION =>
|
records::RTAG_PRESENTATION =>
|
||||||
{let (input, presentation) = PRESENTATION::read_data(input, header.data_size)?;},
|
{(input, presentation) = PRESENTATION::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_PATHTYPE =>
|
records::RTAG_PATHTYPE =>
|
||||||
{let (input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
{(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_WIDTH =>
|
records::RTAG_WIDTH =>
|
||||||
{let (input, width) = WIDTH::read_data(input, header.data_size)?;},
|
{(input, width) = WIDTH::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_STRANS => {
|
records::RTAG_STRANS => {
|
||||||
let (input, strans) = STRANS::read_data(input, header.data_size)?;
|
let result = STRANS::read_data(input, header.data_size)?;
|
||||||
invert_y = strans[0];
|
input = result.0;
|
||||||
|
invert_y = result.1[0];
|
||||||
},
|
},
|
||||||
records::RTAG_MAG =>
|
records::RTAG_MAG =>
|
||||||
{let (input, mag) = MAG::read_data(input, header.data_size)?;},
|
{(input, mag) = MAG::read_data(input, header.data_size)?;},
|
||||||
records::RTAG_ANGLE =>
|
records::RTAG_ANGLE =>
|
||||||
{let (input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
{(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;},
|
||||||
_ =>
|
_ =>
|
||||||
return Err(format!("Unexpected tag {:04x}", header.tag)),
|
return fail(input, format!("Unexpected tag {:04x}", header.tag)),
|
||||||
}
|
}
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
let (input, xy) = XY::read_data(input, header.data_size)?;
|
let (input, xy) = XY::read_data(input, header.data_size)?;
|
||||||
|
|
||||||
let (input, string) = STRING::read(input)?;
|
let (input, string) = STRING::read(input)?;
|
||||||
let (input, properties) = read_properties(input)?;
|
let (input, properties) = read_properties(input)?;
|
||||||
Text{
|
Ok((input, Text{
|
||||||
layer: (layer, dtype),
|
layer: (layer, dtype),
|
||||||
xy: xy,
|
xy: xy,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
@ -444,38 +492,41 @@ impl Element for Text {
|
|||||||
invert_y: invert_y,
|
invert_y: invert_y,
|
||||||
mag: mag,
|
mag: mag,
|
||||||
angle_deg: angle_deg,
|
angle_deg: angle_deg,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: Write>(&self, ww: W) -> OWResult {
|
fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += TEXT::write(ww)?;
|
size += TEXT::write(ww, &())?;
|
||||||
size += LAYER::write(ww, self.layer[0])?;
|
size += LAYER::write(ww, &self.layer.0)?;
|
||||||
size += TEXTTYPE::write(ww, self.layer[1])?;
|
size += TEXTTYPE::write(ww, &self.layer.1)?;
|
||||||
if self.presentation != 0 {
|
if self.presentation.iter().any(|&x| x) {
|
||||||
size += PRESENTATION::write(ww, self.presentation)?;
|
size += PRESENTATION::write(ww, &self.presentation)?;
|
||||||
}
|
}
|
||||||
if self.path_type != 0 {
|
if self.path_type != 0 {
|
||||||
size += PATHTYPE::write(ww, self.path_type)?;
|
size += PATHTYPE::write(ww, &self.path_type)?;
|
||||||
}
|
}
|
||||||
if self.width != 0 {
|
if self.width != 0 {
|
||||||
size += WIDTH::write(ww, self.width)?
|
size += WIDTH::write(ww, &self.width)?
|
||||||
}
|
}
|
||||||
if self.angle_deg != 0 || self.mag != 1 || self.invert_y {
|
if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y {
|
||||||
let strans = [false; 16];
|
let strans = {
|
||||||
strans[0] = self.invert_y;
|
let mut arr = [false; 16];
|
||||||
size += STRANS::write(ww, strans)?;
|
arr[0] = self.invert_y;
|
||||||
if self.mag != 1 {
|
arr
|
||||||
size += MAG::write(ww, self.mag)?;
|
};
|
||||||
|
size += STRANS::write(ww, &strans)?;
|
||||||
|
if self.mag != 1.0 {
|
||||||
|
size += MAG::write(ww, &self.mag)?;
|
||||||
}
|
}
|
||||||
if self.angle_deg !=0 {
|
if self.angle_deg != 0.0 {
|
||||||
size += ANGLE::write(ww, self.angle_deg)?;
|
size += ANGLE::write(ww, &self.angle_deg)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size += XY::write(ww, self.xy)?;
|
size += XY::write(ww, &self.xy)?;
|
||||||
size += STRING::write(ww, self.string)?;
|
size += STRING::write(ww, &self.string)?;
|
||||||
size += write_properties(ww, self.properties)?;
|
size += write_properties(ww, &self.properties)?;
|
||||||
size += ENDEL::write(ww)?;
|
size += ENDEL::write(ww, &())?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
extern crate nom;
|
//#![feature(generic_associated_types)]
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
||||||
pub mod basic;
|
pub mod basic;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
pub mod records;
|
pub mod records;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
|
pub mod library;
|
||||||
|
510
src/library.rs
510
src/library.rs
@ -1,282 +1,392 @@
|
|||||||
/*
|
///
|
||||||
*File-level read/write functionality.
|
/// File-level read/write functionality.
|
||||||
*/
|
///
|
||||||
|
|
||||||
use nom;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::collections:HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use record;
|
use record;
|
||||||
|
use record::{RecordHeader, Record};
|
||||||
use records;
|
use records;
|
||||||
use elements;
|
use elements;
|
||||||
//from .records import HEADER, BGNLIB, ENDLIB, UNITS, LIBNAME
|
use elements::{Element};
|
||||||
//from .records import BGNSTR, STRNAME, ENDSTR, SNAME, COLROW, ENDEL
|
use basic::{IResult, OResult, take_bytes, fail};
|
||||||
//from .records import BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF
|
|
||||||
//from .elements import Element, Reference, Text, Box, Boundary, Path, Node
|
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
pub struct FileHeader {
|
||||||
/*
|
/// Number of user units in one database unit
|
||||||
* Representation of the GDS file header.
|
user_units_per_db_unit: f64,
|
||||||
*
|
/// Number of meters in one database unit
|
||||||
* File header records: HEADER BGNLIB LIBNAME UNITS
|
meters_per_db_unit: f64,
|
||||||
* Optional records are ignored if present and never written.
|
/// Last-modified time [y, m, d, h, m, s]
|
||||||
*
|
mod_time: [i16; 6],
|
||||||
* Version is written as `600`.
|
/// Last-accessed time [y, m, d, h, m, s]
|
||||||
*/
|
acc_time: [i16; 6],
|
||||||
name: Vec<u8>, // Library name
|
/// Library name
|
||||||
user_units_per_db_unit: f64, // Number of user units in one database unit
|
name: Vec<u8>,
|
||||||
meters_per_db_unit: f64, // Number of meters in one database unit
|
|
||||||
mod_time: [u16; 6], // Last-modified time [y, m, d, h, m, s]
|
|
||||||
acc_time: [u16; 6], // Last-accessed time [y, m, d, h, m, s]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileHeader {
|
impl FileHeader {
|
||||||
pub fn new(name: &[u8], meters_per_db_unit: f64, user_units_per_db_unit: f64) -> Self {
|
pub fn new(name: &[u8], meters_per_db_unit: f64, user_units_per_db_unit: f64) -> Self {
|
||||||
FileHeader{
|
FileHeader{
|
||||||
mod_time: [0, 1, 1, 0, 0, 0];
|
mod_time: [0, 1, 1, 0, 0, 0],
|
||||||
acc_time: [0, 1, 1, 0, 0, 0];
|
acc_time: [0, 1, 1, 0, 0, 0],
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
user_units_per_db_unit: user_units_per_db_unit,
|
user_units_per_db_unit: user_units_per_db_unit,
|
||||||
meters_per_db_unit: meters_per_db_unit,
|
meters_per_db_unit: meters_per_db_unit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(input: &[u8]) -> IResult<&[u8], Self> {
|
/// Read and construct a header from the provided input.
|
||||||
/*
|
///
|
||||||
* Read and construct a header from the provided stream.
|
/// Args:
|
||||||
*
|
/// input: Seekable input to read from
|
||||||
* Args:
|
///
|
||||||
* stream: Seekable stream to read from
|
/// Returns:
|
||||||
*
|
/// FileHeader object
|
||||||
* Returns:
|
///
|
||||||
* FileHeader object
|
pub fn read(input: &[u8]) -> IResult<Self> {
|
||||||
*/
|
let (input, _version) = records::HEADER::read(input)?;
|
||||||
let (input, version) = records::HEADER.read(input)?;
|
let (input, [mod_time, acc_time]) = records::BGNLIB::read(input)?;
|
||||||
let (input, (mod_time, acc_time)) = records::BGNLIB.read(input)?;
|
let (input, name) = records::LIBNAME::skip_and_read(input)?;
|
||||||
let (input, name) = records::LIBNAME.skip_and_read(input)?;
|
let (input, (uu, dbu)) = records::UNITS::skip_and_read(input)?;
|
||||||
let (input, (uu, dbu)) = records::UNITS.skip_and_read(input)?;
|
|
||||||
|
|
||||||
FileHeader{
|
Ok((input, FileHeader{
|
||||||
mod_time: mod_time,
|
mod_time: mod_time,
|
||||||
acc_time: acc_time,
|
acc_time: acc_time,
|
||||||
name: name,
|
name: name,
|
||||||
user_units_per_db_unit: uu,
|
user_units_per_db_unit: uu,
|
||||||
meters_per_db_unit: dbu,
|
meters_per_db_unit: dbu,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<W: Write>(&self, ww: W) -> OWResult {
|
/// Write the header to a input
|
||||||
/*
|
///
|
||||||
* Write the header to a stream
|
/// Args:
|
||||||
*
|
/// input: input to write to
|
||||||
* Args:
|
///
|
||||||
* stream: Stream to write to
|
/// Returns:
|
||||||
*
|
/// number of bytes written
|
||||||
* Returns:
|
///
|
||||||
* number of bytes written
|
pub fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
*/
|
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += records::HEADER.write(stream, 600)
|
size += records::HEADER::write(ww, &600)?;
|
||||||
size += records::BGNLIB.write(stream, [self.mod_time, self.acc_time])
|
size += records::BGNLIB::write(ww, &[self.mod_time, self.acc_time])?;
|
||||||
size += records::LIBNAME.write(stream, self.name)
|
size += records::LIBNAME::write(ww, &self.name)?;
|
||||||
size += records::UNITS.write(stream, (self.user_units_per_db_unit, self.meters_per_db_unit))
|
size += records::UNITS::write(ww, &(self.user_units_per_db_unit, self.meters_per_db_unit))?;
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn scan_structs(input: &[u8]) -> HashMap::<Vec<u8>, usize> {
|
///
|
||||||
/*
|
/// Scan through a GDS file, building a table of
|
||||||
* Scan through a GDS file, building a table of
|
/// {b'structure_name': byte_offset}.
|
||||||
* {b'structure_name': byte_offset}.
|
/// The intent of this function is to enable random access
|
||||||
* The intent of this function is to enable random access
|
/// and/or partial (structure-by-structure) reads.
|
||||||
* and/or partial (structure-by-structure) reads.
|
///
|
||||||
*
|
/// Args:
|
||||||
* Args:
|
/// input: Seekable input to read from. Should be positioned
|
||||||
* stream: Seekable stream to read from. Should be positioned
|
/// before the first structure record, but possibly
|
||||||
* before the first structure record, but possibly
|
/// already past the file header.
|
||||||
* already past the file header.
|
///
|
||||||
*/
|
pub fn scan_structs(input: &[u8]) -> IResult<HashMap::<Vec<u8>, usize>> {
|
||||||
let input_size = input.len();
|
let input_size = input.len();
|
||||||
let positions = HashMap{};
|
let mut positions = HashMap::new();
|
||||||
|
|
||||||
let (input, header) = RecordHeader.parse(input)?;
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
while header.tag != records::RTAG_ENDLIB {
|
while header.tag != records::RTAG_ENDLIB {
|
||||||
let (input, _) = nom::bytes::streaming::take(size)(input)?;
|
(input, _) = take_bytes(input, header.data_size)?;
|
||||||
if tag == records::RTAG_BGNSTR {
|
if header.tag == records::RTAG_BGNSTR {
|
||||||
let (input, name) = records::STRNAME.read(input)?;
|
let name;
|
||||||
if positions.conains_key(name) {
|
(input, name) = records::STRNAME::read(input)?;
|
||||||
return Err(format!("Duplicate structure name: {}", name));
|
if positions.contains_key(&name) {
|
||||||
|
return fail(input, format!("Duplicate structure name: {:?}", name));
|
||||||
}
|
}
|
||||||
let position = input_size - input.len();
|
let position = input_size - input.len();
|
||||||
positions.insert(name, position);
|
positions.insert(name, position);
|
||||||
}
|
}
|
||||||
let (input, header) = RecordHeader.parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
positions
|
Ok((input, positions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Cell {
|
pub struct Cell {
|
||||||
|
name: Vec<u8>,
|
||||||
|
|
||||||
|
boundaries: Vec<elements::Boundary>,
|
||||||
|
paths: Vec<elements::Path>,
|
||||||
|
nodes: Vec<elements::Node>,
|
||||||
|
boxes: Vec<elements::GDSBox>,
|
||||||
|
texts: Vec<elements::Text>,
|
||||||
|
refs: Vec<elements::Reference>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cell {
|
impl Cell {
|
||||||
|
/// Build an empty cell
|
||||||
|
pub fn new(name: Vec<u8>) -> 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<Option<Cell>> {
|
||||||
|
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<W: Write>(
|
pub fn write<W: Write>(
|
||||||
&self,
|
&self,
|
||||||
ww: Write,
|
ww: &mut W,
|
||||||
name: &[u8],
|
|
||||||
cre_time: Option<[i16; 6]>,
|
cre_time: Option<[i16; 6]>,
|
||||||
mod_time: Option<[i16; 6]>,
|
mod_time: Option<[i16; 6]>,
|
||||||
) -> OWResult {
|
) -> OResult {
|
||||||
/*
|
|
||||||
* Write a structure to the provided stream.
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
size += BGNSTR.write(ww, (cre_time, mod_time))
|
size += records::BGNSTR::write(ww, &[cre_time.unwrap_or(DEFAULT_DATE),
|
||||||
size += STRNAME.write(ww, name)
|
mod_time.unwrap_or(DEFAULT_DATE)])?;
|
||||||
size += cell.write(ww)
|
size += records::STRNAME::write(ww, &self.name)?;
|
||||||
size += ENDSTR.write(ww)
|
size += self.write_elements(ww)?;
|
||||||
|
size += records::ENDSTR::write(ww, &())?;
|
||||||
|
Ok(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_elements<W: Write>(&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)
|
Ok(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_read_struct(input: &[u8]) -> IResult<&[u8], Option<(Vec<u8>, Cell>)> {
|
|
||||||
/*
|
|
||||||
* Skip to the next structure and attempt to read it.
|
|
||||||
*
|
|
||||||
* Args:
|
|
||||||
* stream: Seekable stream to read from.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* (name, elements) if a structure was found.
|
|
||||||
* None if no structure was found before the end of the library.
|
|
||||||
*/
|
|
||||||
let (input, success) = records::BGNSTR.skip_past(input)?;
|
|
||||||
if !success {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
let (input, name) = records::STRNAME.read(input)?;
|
///
|
||||||
let (input, elements) = Cell::read_elements(input)?;
|
/// Scan through a GDS file, building a table of instance counts
|
||||||
Some((name, elements))
|
/// `{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::<Vec<u8>, HashMap::<Vec<u8>, u32>>> {
|
||||||
|
let mut structures = HashMap::new();
|
||||||
|
|
||||||
|
|
||||||
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
pub fn read_elements(stream: BinaryIO) -> List[Element] {
|
|
||||||
/*
|
|
||||||
* Read elements from the stream until an ENDSTR
|
|
||||||
* record is encountered. The ENDSTR record is also
|
|
||||||
* consumed.
|
|
||||||
*
|
|
||||||
* Args:
|
|
||||||
* stream: Seekable stream to read from.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* List of element objects.
|
|
||||||
*/
|
|
||||||
let (input, header) = RecordHeader.parse(input)?;
|
|
||||||
while header.tag != records::RTAG_ENDSTR {
|
|
||||||
match header.tag {
|
|
||||||
records::RTAG_BOUNDARY => {
|
|
||||||
let (input, boundary) = records::BOUNDARY.read(input)?;
|
|
||||||
cell.boundaries.insert(boundary);
|
|
||||||
},
|
|
||||||
records::RTAG_PATH => {
|
|
||||||
let (input, path) = records::PATH.read(input)?;
|
|
||||||
cell.paths.insert(path);
|
|
||||||
},
|
|
||||||
records::RTAG_NODE => {
|
|
||||||
let (input, node) = records::NODE.read(input)?;
|
|
||||||
cell.nodes.insert(node);
|
|
||||||
},
|
|
||||||
records::RTAG_BOX => {
|
|
||||||
let (input, gds_box) = records::BOX.read(input)?;
|
|
||||||
cell.boxes.insert(gds_box);
|
|
||||||
},
|
|
||||||
records::RTAG_TEXT => {
|
|
||||||
let (input, txt) = records::TEXT.read(input)?;
|
|
||||||
cell.texts.insert(txt);
|
|
||||||
},
|
|
||||||
records::RTAG_SREF => {
|
|
||||||
let (input, sref) = records::SREF.read(input)?;
|
|
||||||
cell.refs.insert(sref);
|
|
||||||
},
|
|
||||||
records::RTAG_AREF => {
|
|
||||||
let (input, aref) = records::AREF.read(input)?;
|
|
||||||
cell.refs.insert(aref);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
// don't care, skip
|
|
||||||
let (input, _) = nom::bytes::streaming::take(size)(input)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (input, header) = RecordHeader.parse(input)?;
|
|
||||||
}
|
|
||||||
Ok((input, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn scan_hierarchy(input: &[u8]) -> IResult<&[u8], HashMap::<Vec<u8>, HashMap::<Vec<u8>, u32>>> {
|
|
||||||
/*
|
|
||||||
* 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:
|
|
||||||
* stream: Seekable stream to read from. Should be positioned
|
|
||||||
* before the first structure record, but possibly
|
|
||||||
* already past the file header.
|
|
||||||
*/
|
|
||||||
let structures = HashMap{};
|
|
||||||
|
|
||||||
let mut ref_name = None
|
|
||||||
let mut ref_count = None
|
|
||||||
let mut cur_structure = HashMap{};
|
|
||||||
|
|
||||||
let (input, header) = Record.read_header(stream)
|
|
||||||
while header.tag != records::RTAG_ENDLIB {
|
while header.tag != records::RTAG_ENDLIB {
|
||||||
match header.tag {
|
match header.tag {
|
||||||
records::RTAG_BGNSTR => {
|
records::RTAG_BGNSTR => {
|
||||||
let (input, _) = nom::bytes::streaming::take(size)(input)?;
|
(input, _) = take_bytes(input, header.data_size)?;
|
||||||
let (input, name) = records::STRNAME.read(input)?;
|
let result = records::STRNAME::read(input)?;
|
||||||
if structures.contains_key(name) {
|
input = result.0;
|
||||||
return Err(format!("Duplicate structure name: {}", name));
|
let name = result.1;
|
||||||
|
if structures.contains_key(&name) {
|
||||||
|
return fail(input, format!("Duplicate structure name: {:?}", name));
|
||||||
}
|
}
|
||||||
cur_structure = HashMap{};
|
let mut cur_structure = HashMap::new();
|
||||||
|
let mut ref_name = None;
|
||||||
|
let mut ref_count = None;
|
||||||
structures.insert(name, cur_structure);
|
structures.insert(name, cur_structure);
|
||||||
ref_name = None;
|
ref_name = None;
|
||||||
ref_count = None;
|
ref_count = None;
|
||||||
},
|
},
|
||||||
records::RTAG_SNAME => {
|
records::RTAG_SNAME => {
|
||||||
let (input, sname) = SNAME.read_data(input, header.data_size)?;
|
let result = records::SNAME::read_data(input, header.data_size)?;
|
||||||
ref_name = Some(sname);
|
input = result.0;
|
||||||
|
ref_name = Some(result.1);
|
||||||
},
|
},
|
||||||
records::RTAG_COLROW => {
|
records::RTAG_COLROW => {
|
||||||
let (input, colrow) = COLROW.read_data(input, header.data_size);
|
let result = records::COLROW::read_data(input, header.data_size)?;
|
||||||
ref_count = colrow[0] * colrow[1];
|
input = result.0;
|
||||||
|
let (col, row) = (result.1[0], result.1[1]);
|
||||||
|
ref_count = Some((col * row) as u32);
|
||||||
},
|
},
|
||||||
records::RTAG_ENDEL => {
|
records::RTAG_ENDEL => {
|
||||||
*cur_structure.entry(ref_name.unwrap()).or_insert(0) += ref_count.unwrap_or(1);
|
*cur_structure.entry(ref_name.unwrap()).or_insert(0) += ref_count.unwrap_or(1);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let (input, _) = nom::bytes::streaming::take(size)(input)?;
|
(input, _) = take_bytes(input, header.data_size)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
let (input, header) = RecordHeader.parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
structures
|
Ok((input, structures))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while header.tag != records::RTAG_ENDLIB {
|
||||||
|
|
||||||
|
pub fn count_ref(input: &[u8]) -> IResult<Option((Vec<u8>, u32))> {
|
||||||
|
let (input, found_struc) = records::BGNSTR.skip_past(input)?;
|
||||||
|
if not 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)?;
|
||||||
}
|
}
|
||||||
|
390
src/record.rs
390
src/record.rs
@ -1,18 +1,15 @@
|
|||||||
/*
|
///
|
||||||
* Generic record-level read/write functionality.
|
/// Generic record-level read/write functionality.
|
||||||
*/
|
///
|
||||||
use nom::IResult;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use byteorder::BigEndian;
|
use std::convert::TryInto;
|
||||||
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
|
|
||||||
|
|
||||||
use basic::{pack_datetime, pack_bitarray, pack_ascii, pack_int2, pack_int4, pack_real8}; #[warn(unused_imports)]
|
use basic::{pack_datetime, pack_bitarray, pack_ascii, pack_int2, pack_int4, pack_real8}; #[warn(unused_imports)]
|
||||||
use basic::{parse_datetime, parse_bitarray, parse_ascii, parse_int2, parse_int4, parse_real8}; #[warn(unused_imports)]
|
use basic::{parse_datetime, parse_bitarray, parse_ascii, parse_int2, parse_int4, parse_real8}; #[warn(unused_imports)]
|
||||||
use basic::{OWResult};
|
use basic::{OResult, IResult, fail, parse_u16, take_bytes};
|
||||||
use records;
|
use records;
|
||||||
//from .basic import parse_int2, parse_int4, parse_real8, parse_datetime, parse_bitarray
|
|
||||||
//from .basic import pack_int2, pack_int4, pack_real8, pack_datetime, pack_bitarray
|
|
||||||
//from .basic import parse_ascii, read
|
|
||||||
|
|
||||||
|
|
||||||
//#[no_mangle]
|
//#[no_mangle]
|
||||||
@ -26,37 +23,45 @@ pub struct RecordHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RecordHeader {
|
impl RecordHeader {
|
||||||
pub fn parse(input: &[u8]) -> IResult<&[u8], RecordHeader> {
|
pub fn read(input: &[u8]) -> IResult<RecordHeader> {
|
||||||
let (_, size) = nom::number::streaming::be_u16(input[0..])?;
|
let (input, size) = parse_u16(input)?;
|
||||||
let (_, tag) = nom::number::streaming::be_u16(input[2..])?;
|
let (input, tag) = parse_u16(input)?;
|
||||||
Ok((input[4..], RecordHeader{tag:tag, data_size:size - 4}))
|
Ok((input, RecordHeader{tag:tag, data_size:size - 4}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pack(self) -> [u8; 4] {
|
pub fn pack_into(&self) -> [u8; 4] {
|
||||||
assert!(self.size < 0xffff - 4, "Record too big!");
|
assert!(self.data_size < 0xffff - 4, "Record too big!");
|
||||||
let vals = [self.size, self.tag];
|
let vals = [self.data_size, self.tag];
|
||||||
let mut buf = [0x77; 4];
|
let mut buf = [0x77; 4];
|
||||||
BigEndian::write_u16_into(&vals, &mut buf);
|
BigEndian::write_u16_into(&vals, &mut buf);
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<W: Write>(&self, ww: W) -> OWResult {
|
pub fn write<W: Write>(&self, ww: &mut W) -> OResult {
|
||||||
let bytes = self.pack();
|
let bytes = self.pack_into();
|
||||||
ww.write(bytes)
|
ww.write(&bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait Record {
|
pub trait RecordData {
|
||||||
fn tag() -> u32;
|
type BareData;
|
||||||
fn expected_size() -> Option<usize>;
|
type InData : ?Sized;
|
||||||
|
type ByteData : AsRef<[u8]>;
|
||||||
|
|
||||||
//fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Self>;
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData>;
|
||||||
|
fn pack_into(buf: &mut [u8], data: &Self::InData);
|
||||||
|
//fn size(data: &Self::BareData) -> u16;
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Record {
|
|
||||||
pub fn check_size(&self, actual_size: usize) -> Result<(), &str> {
|
pub trait Record<RData: RecordData> {
|
||||||
match self.expected_size() {
|
fn tag() -> u16;
|
||||||
|
fn expected_size() -> Option<u16>;
|
||||||
|
|
||||||
|
fn check_size(actual_size: u16) -> Result<(), String> {
|
||||||
|
match Self::expected_size() {
|
||||||
Some(size) => if size == actual_size {
|
Some(size) => if size == actual_size {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -66,154 +71,323 @@ impl Record {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_header(input: &[u8]) -> IResult<&[u8], RecordHeader> {
|
fn read_header(input: &[u8]) -> IResult<RecordHeader> {
|
||||||
RecordHeader::parse(input)
|
RecordHeader::read(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_header<W: Write>(ww: W, data_size: usize) -> OWResult {
|
fn write_header<W: Write>(ww: &mut W, data_size: u16) -> OResult {
|
||||||
RecordHeader{tag: Self.tag(), size: data_size}.write(ww)
|
RecordHeader{tag: Self::tag(), data_size: data_size}.write(ww)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_past(input: &[u8]) -> IResult<&[u8], bool> {
|
fn read_data(input: &[u8], size: u16) -> IResult<RData::BareData> {
|
||||||
/*
|
RData::read(input, size)
|
||||||
* Skip to the end of the next occurence of this record.
|
}
|
||||||
*
|
|
||||||
* Return:
|
fn pack_data(buf: &mut [u8], data: &RData::InData) {
|
||||||
* True if the record was encountered and skipped.
|
RData::pack_into(buf, data)
|
||||||
* False if the end of the library was reached.
|
}
|
||||||
*/
|
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
///
|
||||||
while header.tag != Self.tag() {
|
/// Skip to the end of the next occurence of this record.
|
||||||
let (input, _) = nom::bytes::streaming::take(header.size)?;
|
///
|
||||||
|
/// Return:
|
||||||
|
/// True if the record was encountered and skipped.
|
||||||
|
/// False if the end of the library was reached.
|
||||||
|
///
|
||||||
|
fn skip_past(input: &[u8]) -> IResult<bool> {
|
||||||
|
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 {
|
if header.tag == records::RTAG_ENDLIB {
|
||||||
return Ok((input, false))
|
return Ok((original_input, false))
|
||||||
}
|
}
|
||||||
let (input, header) = RecordHeader::parse(input)?;
|
(input, header) = RecordHeader::read(input)?;
|
||||||
}
|
}
|
||||||
let (input, _) = nom::bytes::streaming::take(header.size)?;
|
(input, _) = take_bytes(input, header.data_size)?;
|
||||||
Ok((input, true))
|
Ok((input, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
fn skip_and_read(input: &[u8]) -> IResult<RData::BareData> {
|
||||||
pub fn skip_and_read(input: &[u8]) -> IResult<&[u8], bool>{
|
let (mut input, mut header) = RecordHeader::read(input)?;
|
||||||
size, tag = Record.read_header(stream)
|
while header.tag != Self::tag() {
|
||||||
while tag != cls.tag{
|
(input, _) = take_bytes(input, header.data_size)?;
|
||||||
stream.seek(size, io.SEEK_CUR)
|
(input, header) = RecordHeader::read(input)?;
|
||||||
size, tag = Record.read_header(stream)
|
|
||||||
}
|
}
|
||||||
data = cls.read_data(stream, size)
|
let (input, data) = Self::read_data(input, header.data_size)?;
|
||||||
return data
|
Ok((input, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
def read(cls: Type[R], stream: BinaryIO){
|
fn expect_header(input: &[u8]) -> IResult<u16> {
|
||||||
size = expect_record(stream, cls.tag)
|
let (input, header) = RecordHeader::read(input)?;
|
||||||
data = cls.read_data(stream, size)
|
if header.tag != Self::tag() {
|
||||||
return data
|
fail(input, format!("Unexpected record! Got tag 0x{:04x}, expected 0x{:04x}", header.tag, Self::tag()))
|
||||||
|
} else {
|
||||||
|
Ok((input, header.data_size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def write(cls, stream: BinaryIO, data) -> int {
|
fn read(input: &[u8]) -> IResult<RData::BareData> {
|
||||||
data_bytes = cls.pack_data(data)
|
let (input, size) = Self::expect_header(input)?;
|
||||||
b = cls.write_header(stream, len(data_bytes))
|
Self::check_size(size).unwrap();
|
||||||
b += stream.write(data_bytes)
|
let (input, data) = Self::read_data(input, size)?;
|
||||||
return b
|
Ok((input, data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: 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];
|
||||||
|
|
||||||
pub trait BitArray {
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], [bool; 16]> {
|
assert!(size == 2);
|
||||||
parse_bitarray(input)
|
parse_bitarray(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], vals: &[bool; 16]) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_bitarray(&mut buf, vals)
|
pack_bitarray(buf, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData {
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
Self::pack_into(&mut buf, data);
|
||||||
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Int2 {
|
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], i16> {
|
pub struct Int2;
|
||||||
|
impl RecordData for Int2 {
|
||||||
|
type BareData = i16;
|
||||||
|
type InData = i16;
|
||||||
|
type ByteData = [u8; 2];
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
assert!(size == 2);
|
||||||
parse_int2(input)
|
parse_int2(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], val: i16) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_int2(&mut buf, val)
|
pack_int2(buf, *data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData {
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
Self::pack_into(&mut buf, data);
|
||||||
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Int4 {
|
pub struct Int4;
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], i32> {
|
impl RecordData for Int4 {
|
||||||
|
type BareData = i32;
|
||||||
|
type InData = i32;
|
||||||
|
type ByteData = [u8; 4];
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
assert!(size == 4);
|
||||||
parse_int4(input)
|
parse_int4(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], val: i32) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_int4(&mut buf, val)
|
pack_int4(buf, *data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData {
|
||||||
|
let mut buf = [0; 4];
|
||||||
|
Self::pack_into(&mut buf, data);
|
||||||
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Int2Array {
|
|
||||||
fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Vec<i16>> {
|
pub struct Int2Array;
|
||||||
|
impl RecordData for Int2Array {
|
||||||
|
type BareData = Vec<i16>;
|
||||||
|
type InData = [i16];
|
||||||
|
type ByteData = Vec<u8>;
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
assert!(size % 2 == 0, "Record must contain an integer quantity of integers");
|
assert!(size % 2 == 0, "Record must contain an integer quantity of integers");
|
||||||
nom::multi::count(parse_int2, size / 2)(input)
|
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_data(buf: &mut [u8], vals: &[i16]) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
BigEndian::write_i16_into(&vals, &mut buf)
|
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<i32>;
|
||||||
|
type InData = [i32];
|
||||||
|
type ByteData = Vec<u8>;
|
||||||
|
|
||||||
pub trait Int4Array {
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
fn parse_data(input: &[u8], size: usize) -> IResult<&[u8], Vec<i32>> {
|
|
||||||
assert!(size % 4 == 0, "Record must contain an integer quantity of integers");
|
assert!(size % 4 == 0, "Record must contain an integer quantity of integers");
|
||||||
nom::multi::count(parse_int4, size / 4)(input)
|
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_data(buf: &mut [u8], vals: &[i32]) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
BigEndian::write_i32_into(&vals, &mut buf)
|
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 trait Real8 {
|
pub struct Real8;
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], f64> {
|
impl RecordData for Real8 {
|
||||||
|
type BareData = f64;
|
||||||
|
type InData = f64;
|
||||||
|
type ByteData = [u8; 8];
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
assert!(size == 8);
|
||||||
parse_real8(input)
|
parse_real8(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], val: f64) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_real8(&mut buf, val)
|
pack_real8(buf, *data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData {
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
Self::pack_into(&mut buf, data);
|
||||||
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ASCII {
|
pub struct Real8Pair;
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
|
impl RecordData for Real8Pair {
|
||||||
parse_ascii(input)
|
type BareData = (f64, f64);
|
||||||
|
type InData = (f64, f64);
|
||||||
|
type ByteData = [u8; 2 * 8];
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
assert!(size == 2 * 8);
|
||||||
|
let (input, data0) = parse_real8(input)?;
|
||||||
|
let (input, data1) = parse_real8(input)?;
|
||||||
|
Ok((input, (data0, data1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], data: &[u8]) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_ascii(&mut buf, data)
|
pack_real8(&mut buf[8 * 0..], data.0);
|
||||||
|
pack_real8(&mut buf[8 * 1..], data.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(data: &Self::InData) -> Self::ByteData {
|
||||||
|
let mut buf = [0; 2 * 8];
|
||||||
|
Self::pack_into(&mut buf, data);
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
//fn write<W: 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<u8>;
|
||||||
|
type InData = [u8];
|
||||||
|
type ByteData = Vec<u8>;
|
||||||
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
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 trait DateTime {
|
|
||||||
fn parse_data(input: &[u8]) -> IResult<&[u8], [u16; 6]> {
|
pub struct DateTimePair;
|
||||||
parse_datetime(input)
|
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<Self::BareData> {
|
||||||
|
assert!(size == 2 * 6 * 2);
|
||||||
|
let (input, data0) = parse_datetime(input)?;
|
||||||
|
let (input, data1) = parse_datetime(input)?;
|
||||||
|
Ok((input, [data0, data1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_data(buf: &mut [u8], data: [u16; 6]) {
|
fn pack_into(buf: &mut [u8], data: &Self::InData) {
|
||||||
pack_datetime(&mut buf, data)
|
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<W: Write>(ww: &mut W, data: &Self::BareData) -> OResult {
|
||||||
|
// let mut buf = [u8; 2 * 6 * 2];
|
||||||
|
// Self::pack_into(&mut buf, data)
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DTR: DateTime + Record> DTR {
|
pub struct Empty;
|
||||||
fn skip_and_read(input: &[u8]) -> IResult<&[u8], [DTR; 2]> {
|
impl RecordData for Empty {
|
||||||
let mut header = Self.read_header(input)?;
|
type BareData = ();
|
||||||
while header.tag != Self.tag() {
|
type InData = ();
|
||||||
nom::bytes::streaming::take(header.data_size)?;
|
type ByteData = [u8; 0];
|
||||||
header = Self.read_header(input)?;
|
|
||||||
|
fn read(input: &[u8], size: u16) -> IResult<Self::BareData> {
|
||||||
|
assert!(size == 0);
|
||||||
|
Ok((input, ()))
|
||||||
}
|
}
|
||||||
assert!(header.data_size == 6 * 2);
|
|
||||||
let data0 = Self.read_data(&input)?;
|
fn pack_into(_buf: &mut [u8], _data: &Self::InData) {
|
||||||
let data1 = Self.read_data(&input)?;
|
|
||||||
Ok([data0, data1])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pack(_data: &Self::InData) -> Self::ByteData {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
//fn write<W: Write>(ww: &mut W, data: &Self::BareData) {
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
482
src/records.rs
482
src/records.rs
@ -1,9 +1,8 @@
|
|||||||
/*
|
///
|
||||||
* Record type and tag definitions
|
/// Record type and tag definitions
|
||||||
*/
|
///
|
||||||
|
|
||||||
use record::{Record, Int2, Int4, Int2Array, Int4Array, Real8, DateTime, BitArray, ASCII};
|
use record::{Record, Int2, Int4, Int2Array, Int4Array, Real8, Real8Pair, DateTimePair, BitArray, ASCII, Empty};
|
||||||
//use basic::{OWResult};
|
|
||||||
|
|
||||||
//use std::io::Write;
|
//use std::io::Write;
|
||||||
|
|
||||||
@ -91,7 +90,7 @@ pub const DATA_TYPE_STR: u16 = 0x06;
|
|||||||
pub const MAX_DATA_SIZE: usize = 8;
|
pub const MAX_DATA_SIZE: usize = 8;
|
||||||
|
|
||||||
/// Returns the size of the given data type in bytes.
|
/// Returns the size of the given data type in bytes.
|
||||||
pub fn data_size(t: u16) -> usize {
|
pub fn data_size(t: u16) -> Option<u16> {
|
||||||
match t {
|
match t {
|
||||||
x if x == DATA_TYPE_NONE => 0,
|
x if x == DATA_TYPE_NONE => 0,
|
||||||
x if x == DATA_TYPE_BIT => 2,
|
x if x == DATA_TYPE_BIT => 2,
|
||||||
@ -103,215 +102,195 @@ pub fn data_size(t: u16) -> usize {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub struct HEADER {}
|
pub struct HEADER;
|
||||||
impl Record for HEADER {
|
impl Record<Int2> for HEADER {
|
||||||
fn tag() -> u16 { RTAG_HEADER }
|
fn tag() -> u16 { RTAG_HEADER }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for HEADER {}
|
//impl Record<Int2> for HEADER;
|
||||||
|
|
||||||
pub struct BGNLIB {}
|
pub struct BGNLIB;
|
||||||
impl Record for BGNLIB {
|
impl Record<DateTimePair> for BGNLIB {
|
||||||
fn tag() -> u16 { RTAG_BGNLIB }
|
fn tag() -> u16 { RTAG_BGNLIB }
|
||||||
fn expected_size() -> usize { Some(2 * 6) }
|
fn expected_size() -> Option<u16> { Some(2 * 6) }
|
||||||
}
|
}
|
||||||
impl DateTime for BGNLIB {}
|
|
||||||
|
|
||||||
pub struct LIBNAME {}
|
pub struct LIBNAME;
|
||||||
impl Record for LIBNAME {
|
impl Record<ASCII> for LIBNAME {
|
||||||
fn tag() -> u16 { RTAG_LIBNAME }
|
fn tag() -> u16 { RTAG_LIBNAME }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for LIBNAME {}
|
|
||||||
|
|
||||||
pub struct UNITS {}
|
pub struct UNITS;
|
||||||
impl Record for UNITS {
|
impl Record<Real8Pair> for UNITS {
|
||||||
// (user_units_per_db_unit, db_units_per_meter)
|
// (user_units_per_db_unit, db_units_per_meter)
|
||||||
fn tag() -> u16 { RTAG_UNITS }
|
fn tag() -> u16 { RTAG_UNITS }
|
||||||
fn expected_size() -> usize { Some(2 * 8) }
|
fn expected_size() -> Option<u16> { Some(2 * 8) }
|
||||||
}
|
}
|
||||||
impl Real8 for UNITS {}
|
|
||||||
|
|
||||||
pub struct ENDLIB {}
|
pub struct ENDLIB;
|
||||||
impl Record for ENDLIB {
|
impl Record<Empty> for ENDLIB {
|
||||||
fn tag() -> u16 { RTAG_ENDLIB }
|
fn tag() -> u16 { RTAG_ENDLIB }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BGNSTR {}
|
pub struct BGNSTR;
|
||||||
impl Record for BGNSTR {
|
impl Record<DateTimePair> for BGNSTR {
|
||||||
fn tag() -> u16 { RTAG_BGNSTR }
|
fn tag() -> u16 { RTAG_BGNSTR }
|
||||||
fn expected_size() -> usize { Some(2 * 6) }
|
fn expected_size() -> Option<u16> { Some(2 * 6) }
|
||||||
}
|
}
|
||||||
impl DateTime for ENDLIB {}
|
|
||||||
|
|
||||||
pub struct STRNAME {}
|
pub struct STRNAME;
|
||||||
impl Record for STRNAME {
|
impl Record<ASCII> for STRNAME {
|
||||||
fn tag() -> u16 { RTAG_STRNAME }
|
fn tag() -> u16 { RTAG_STRNAME }
|
||||||
fn expected_size() -> usize { Some(2 * 6) }
|
fn expected_size() -> Option<u16> { Some(2 * 6) }
|
||||||
}
|
}
|
||||||
impl ASCII for STRNAME {}
|
|
||||||
|
|
||||||
pub struct ENDSTR {}
|
pub struct ENDSTR;
|
||||||
impl Record for ENDSTR {
|
impl Record<Empty> for ENDSTR {
|
||||||
fn tag() -> u16 { RTAG_ENDSTR }
|
fn tag() -> u16 { RTAG_ENDSTR }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BOUNDARY {}
|
pub struct BOUNDARY;
|
||||||
impl Record for BOUNDARY {
|
impl Record<Empty> for BOUNDARY {
|
||||||
fn tag() -> u16 { RTAG_BOUNDARY }
|
fn tag() -> u16 { RTAG_BOUNDARY }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PATH {}
|
pub struct PATH;
|
||||||
impl Record for PATH {
|
impl Record<Empty> for PATH {
|
||||||
fn tag() -> u16 { RTAG_PATH }
|
fn tag() -> u16 { RTAG_PATH }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SREF {}
|
pub struct SREF;
|
||||||
impl Record for SREF {
|
impl Record<Empty> for SREF {
|
||||||
fn tag() -> u16 { RTAG_SREF }
|
fn tag() -> u16 { RTAG_SREF }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AREF {}
|
pub struct AREF;
|
||||||
impl Record for AREF {
|
impl Record<Empty> for AREF {
|
||||||
fn tag() -> u16 { RTAG_AREF }
|
fn tag() -> u16 { RTAG_AREF }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TEXT {}
|
pub struct TEXT;
|
||||||
impl Record for TEXT {
|
impl Record<Empty> for TEXT {
|
||||||
fn tag() -> u16 { RTAG_TEXT }
|
fn tag() -> u16 { RTAG_TEXT }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LAYER {}
|
pub struct LAYER;
|
||||||
impl Record for LAYER {
|
impl Record<Int2> for LAYER {
|
||||||
fn tag() -> u16 { RTAG_LAYER }
|
fn tag() -> u16 { RTAG_LAYER }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for LAYER {}
|
|
||||||
|
|
||||||
pub struct DATATYPE {}
|
pub struct DATATYPE;
|
||||||
impl Record for DATATYPE {
|
impl Record<Int2> for DATATYPE {
|
||||||
fn tag() -> u16 { RTAG_DATATYPE }
|
fn tag() -> u16 { RTAG_DATATYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for DATATYPE {}
|
|
||||||
|
|
||||||
pub struct WIDTH {}
|
pub struct WIDTH;
|
||||||
impl Record for WIDTH {
|
impl Record<Int4> for WIDTH {
|
||||||
fn tag() -> u16 { RTAG_WIDTH }
|
fn tag() -> u16 { RTAG_WIDTH }
|
||||||
fn expected_size() -> usize { Some(4) }
|
fn expected_size() -> Option<u16> { Some(4) }
|
||||||
}
|
}
|
||||||
impl Int4 for WIDTH {}
|
|
||||||
|
|
||||||
pub struct XY {}
|
pub struct XY;
|
||||||
impl Record for XY {
|
impl Record<Int4Array> for XY {
|
||||||
fn tag() -> u16 { RTAG_XY }
|
fn tag() -> u16 { RTAG_XY }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl Int4Array for XY {}
|
|
||||||
|
|
||||||
pub struct ENDEL {}
|
pub struct ENDEL;
|
||||||
impl Record for ENDEL {
|
impl Record<Empty> for ENDEL {
|
||||||
fn tag() -> u16 { RTAG_ENDEL }
|
fn tag() -> u16 { RTAG_ENDEL }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SNAME {}
|
pub struct SNAME;
|
||||||
impl Record for SNAME {
|
impl Record<ASCII> for SNAME {
|
||||||
fn tag() -> u16 { RTAG_SNAME }
|
fn tag() -> u16 { RTAG_SNAME }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for SNAME {}
|
|
||||||
|
|
||||||
pub struct COLROW {}
|
pub struct COLROW;
|
||||||
impl Record for COLROW {
|
impl Record<Int2Array> for COLROW {
|
||||||
fn tag() -> u16 { RTAG_COLROW }
|
fn tag() -> u16 { RTAG_COLROW }
|
||||||
fn expected_size() -> usize { Some(4) }
|
fn expected_size() -> Option<u16> { Some(4) }
|
||||||
}
|
}
|
||||||
impl Int2Array for COLROW {}
|
|
||||||
|
|
||||||
pub struct NODE {}
|
pub struct NODE;
|
||||||
impl Record for NODE {
|
impl Record<Empty> for NODE {
|
||||||
fn tag() -> u16 { RTAG_NODE }
|
fn tag() -> u16 { RTAG_NODE }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TEXTTYPE {}
|
pub struct TEXTTYPE;
|
||||||
impl Record for TEXTTYPE {
|
impl Record<Int2> for TEXTTYPE {
|
||||||
fn tag() -> u16 { RTAG_TEXTTYPE }
|
fn tag() -> u16 { RTAG_TEXTTYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for TEXTTYPE {}
|
|
||||||
|
|
||||||
pub struct PRESENTATION {}
|
pub struct PRESENTATION;
|
||||||
impl Record for PRESENTATION {
|
impl Record<BitArray> for PRESENTATION {
|
||||||
fn tag() -> u16 { RTAG_PRESENTATION }
|
fn tag() -> u16 { RTAG_PRESENTATION }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl BitArray for PRESENTATION {}
|
|
||||||
|
|
||||||
pub struct SPACING {}
|
pub struct SPACING;
|
||||||
impl Record for SPACING {
|
impl Record<Int2> for SPACING {
|
||||||
fn tag() -> u16 { RTAG_SPACING }
|
fn tag() -> u16 { RTAG_SPACING }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for SPACING {}
|
|
||||||
|
|
||||||
pub struct STRING {}
|
pub struct STRING;
|
||||||
impl Record for STRING {
|
impl Record<ASCII> for STRING {
|
||||||
fn tag() -> u16 { RTAG_STRING }
|
fn tag() -> u16 { RTAG_STRING }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for STRING {}
|
|
||||||
|
|
||||||
pub struct STRANS {}
|
pub struct STRANS;
|
||||||
impl Record for STRANS {
|
impl Record<BitArray> for STRANS {
|
||||||
fn tag() -> u16 { RTAG_STRANS }
|
fn tag() -> u16 { RTAG_STRANS }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl BitArray for STRANS {}
|
|
||||||
|
|
||||||
pub struct MAG {}
|
pub struct MAG;
|
||||||
impl Record for MAG {
|
impl Record<Real8> for MAG {
|
||||||
fn tag() -> u16 { RTAG_MAG }
|
fn tag() -> u16 { RTAG_MAG }
|
||||||
fn expected_size() -> usize { Some(8) }
|
fn expected_size() -> Option<u16> { Some(8) }
|
||||||
}
|
}
|
||||||
impl Real8 for MAG {}
|
|
||||||
|
|
||||||
pub struct ANGLE {}
|
pub struct ANGLE;
|
||||||
impl Record for ANGLE {
|
impl Record<Real8> for ANGLE {
|
||||||
fn tag() -> u16 { RTAG_ANGLE }
|
fn tag() -> u16 { RTAG_ANGLE }
|
||||||
fn expected_size() -> usize { Some(8) }
|
fn expected_size() -> Option<u16> { Some(8) }
|
||||||
}
|
}
|
||||||
impl Real8 for ANGLE {}
|
|
||||||
|
|
||||||
pub struct UINTEGER {}
|
pub struct UINTEGER;
|
||||||
impl Record for UINTEGER {
|
impl Record<Int2> for UINTEGER {
|
||||||
fn tag() -> u16 { RTAG_UINTEGER }
|
fn tag() -> u16 { RTAG_UINTEGER }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for UINTEGER {}
|
|
||||||
|
|
||||||
pub struct USTRING {}
|
pub struct USTRING;
|
||||||
impl Record for USTRING {
|
impl Record<ASCII> for USTRING {
|
||||||
fn tag() -> u16 { RTAG_USTRING }
|
fn tag() -> u16 { RTAG_USTRING }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for USTRING {}
|
|
||||||
|
|
||||||
pub struct REFLIBS {}
|
pub struct REFLIBS;
|
||||||
impl Record for REFLIBS {
|
impl Record<ASCII> for REFLIBS {
|
||||||
fn tag() -> u16 { RTAG_REFLIBS }
|
fn tag() -> u16 { RTAG_REFLIBS }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl REFLIBS {
|
impl REFLIBS {
|
||||||
fn check_size(&self, actual_size: usize) -> Result<(), &str> {
|
fn check_size(actual_size: usize) -> Result<(), String> {
|
||||||
if actual_size % 44 == 0 {
|
if actual_size % 44 == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -319,15 +298,14 @@ impl REFLIBS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ASCII for REFLIBS {}
|
|
||||||
|
|
||||||
pub struct FONTS {}
|
pub struct FONTS;
|
||||||
impl Record for FONTS {
|
impl Record<ASCII> for FONTS {
|
||||||
fn tag() -> u16 { RTAG_FONTS }
|
fn tag() -> u16 { RTAG_FONTS }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl FONTS {
|
impl FONTS {
|
||||||
fn check_size(&self, actual_size: usize) -> Result<(), &str> {
|
fn check_size(actual_size: usize) -> Result<(), String> {
|
||||||
if actual_size % 44 == 0 {
|
if actual_size % 44 == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -335,29 +313,26 @@ impl FONTS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ASCII for FONTS {}
|
|
||||||
|
|
||||||
pub struct PATHTYPE {}
|
pub struct PATHTYPE;
|
||||||
impl Record for PATHTYPE {
|
impl Record<Int2> for PATHTYPE {
|
||||||
fn tag() -> u16 { RTAG_PATHTYPE }
|
fn tag() -> u16 { RTAG_PATHTYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for PATHTYPE {}
|
|
||||||
|
|
||||||
pub struct GENERATIONS {}
|
pub struct GENERATIONS;
|
||||||
impl Record for GENERATIONS {
|
impl Record<Int2> for GENERATIONS {
|
||||||
fn tag() -> u16 { RTAG_GENERATIONS }
|
fn tag() -> u16 { RTAG_GENERATIONS }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for GENERATIONS {}
|
|
||||||
|
|
||||||
pub struct ATTRTABLE {}
|
pub struct ATTRTABLE;
|
||||||
impl Record for ATTRTABLE {
|
impl Record<ASCII> for ATTRTABLE {
|
||||||
fn tag() -> u16 { RTAG_ATTRTABLE }
|
fn tag() -> u16 { RTAG_ATTRTABLE }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ATTRTABLE {
|
impl ATTRTABLE {
|
||||||
fn check_size(&self, actual_size: usize) -> Result<(), &str> {
|
fn check_size(actual_size: usize) -> Result<(), String> {
|
||||||
if actual_size % 44 == 0 {
|
if actual_size % 44 == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -365,231 +340,208 @@ impl ATTRTABLE {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ASCII for ATTRTABLE {}
|
|
||||||
|
|
||||||
pub struct STYPTABLE {}
|
pub struct STYPTABLE;
|
||||||
impl Record for STYPTABLE {
|
impl Record<ASCII> for STYPTABLE {
|
||||||
fn tag() -> u16 { RTAG_STYPTABLE }
|
fn tag() -> u16 { RTAG_STYPTABLE }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for STYPTABLE {}
|
|
||||||
|
|
||||||
pub struct STRTYPE {}
|
pub struct STRTYPE;
|
||||||
impl Record for STRTYPE {
|
impl Record<Int2> for STRTYPE {
|
||||||
fn tag() -> u16 { RTAG_STRTYPE }
|
fn tag() -> u16 { RTAG_STRTYPE }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl Int2 for STRTYPE {}
|
|
||||||
|
|
||||||
pub struct ELFLAGS {}
|
pub struct ELFLAGS;
|
||||||
impl Record for ELFLAGS {
|
impl Record<BitArray> for ELFLAGS {
|
||||||
fn tag() -> u16 { RTAG_ELFLAGS }
|
fn tag() -> u16 { RTAG_ELFLAGS }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl BitArray for ELFLAGS {}
|
|
||||||
|
|
||||||
pub struct ELKEY {}
|
pub struct ELKEY;
|
||||||
impl Record for ELKEY {
|
impl Record<Int2> for ELKEY {
|
||||||
fn tag() -> u16 { RTAG_ELKEY }
|
fn tag() -> u16 { RTAG_ELKEY }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for ELKEY {}
|
|
||||||
|
|
||||||
pub struct LINKTYPE {}
|
pub struct LINKTYPE;
|
||||||
impl Record for LINKTYPE {
|
impl Record<Int2> for LINKTYPE {
|
||||||
fn tag() -> u16 { RTAG_LINKTYPE }
|
fn tag() -> u16 { RTAG_LINKTYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for LINKTYPE {}
|
|
||||||
|
|
||||||
pub struct LINKKEYS {}
|
pub struct LINKKEYS;
|
||||||
impl Record for LINKKEYS {
|
impl Record<Int2> for LINKKEYS {
|
||||||
fn tag() -> u16 { RTAG_LINKKEYS }
|
fn tag() -> u16 { RTAG_LINKKEYS }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for LINKKEYS {}
|
|
||||||
|
|
||||||
pub struct NODETYPE {}
|
pub struct NODETYPE;
|
||||||
impl Record for NODETYPE {
|
impl Record<Int2> for NODETYPE {
|
||||||
fn tag() -> u16 { RTAG_NODETYPE }
|
fn tag() -> u16 { RTAG_NODETYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for NODETYPE {}
|
|
||||||
|
|
||||||
pub struct PROPATTR {}
|
pub struct PROPATTR;
|
||||||
impl Record for PROPATTR {
|
impl Record<Int2> for PROPATTR {
|
||||||
fn tag() -> u16 { RTAG_PROPATTR }
|
fn tag() -> u16 { RTAG_PROPATTR }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for PROPATTR {}
|
|
||||||
|
|
||||||
pub struct PROPVALUE {}
|
pub struct PROPVALUE;
|
||||||
impl Record for PROPVALUE {
|
impl Record<ASCII> for PROPVALUE {
|
||||||
fn tag() -> u16 { RTAG_PROPVALUE }
|
fn tag() -> u16 { RTAG_PROPVALUE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl ASCII for PROPVALUE {}
|
|
||||||
|
|
||||||
pub struct BOX {}
|
pub struct BOX;
|
||||||
impl Record for BOX {
|
impl Record<Empty> for BOX {
|
||||||
fn tag() -> u16 { RTAG_BOX }
|
fn tag() -> u16 { RTAG_BOX }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BOXTYPE {}
|
pub struct BOXTYPE;
|
||||||
impl Record for BOXTYPE {
|
impl Record<Int2> for BOXTYPE {
|
||||||
fn tag() -> u16 { RTAG_BOXTYPE }
|
fn tag() -> u16 { RTAG_BOXTYPE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for BOXTYPE {}
|
|
||||||
|
|
||||||
pub struct PLEX {}
|
pub struct PLEX;
|
||||||
impl Record for PLEX {
|
impl Record<Int4> for PLEX {
|
||||||
fn tag() -> u16 { RTAG_PLEX }
|
fn tag() -> u16 { RTAG_PLEX }
|
||||||
fn expected_size() -> usize { Some(4) }
|
fn expected_size() -> Option<u16> { Some(4) }
|
||||||
}
|
}
|
||||||
impl Int4 for PLEX {}
|
|
||||||
|
|
||||||
pub struct BGNEXTN {}
|
pub struct BGNEXTN;
|
||||||
impl Record for BGNEXTN {
|
impl Record<Int4> for BGNEXTN {
|
||||||
fn tag() -> u16 { RTAG_BGNEXTN }
|
fn tag() -> u16 { RTAG_BGNEXTN }
|
||||||
fn expected_size() -> usize { Some(4) }
|
fn expected_size() -> Option<u16> { Some(4) }
|
||||||
}
|
}
|
||||||
impl Int4 for BGNEXTN {}
|
|
||||||
|
|
||||||
pub struct ENDEXTN {}
|
pub struct ENDEXTN;
|
||||||
impl Record for ENDEXTN {
|
impl Record<Int4> for ENDEXTN {
|
||||||
fn tag() -> u16 { RTAG_ENDEXTN }
|
fn tag() -> u16 { RTAG_ENDEXTN }
|
||||||
fn expected_size() -> usize { Some(4) }
|
fn expected_size() -> Option<u16> { Some(4) }
|
||||||
}
|
}
|
||||||
impl Int4 for ENDEXTN {}
|
|
||||||
|
|
||||||
pub struct TAPENUM {}
|
pub struct TAPENUM;
|
||||||
impl Record for TAPENUM {
|
impl Record<Int2> for TAPENUM {
|
||||||
fn tag() -> u16 { RTAG_TAPENUM }
|
fn tag() -> u16 { RTAG_TAPENUM }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for TAPENUM {}
|
|
||||||
|
|
||||||
pub struct TAPECODE {}
|
pub struct TAPECODE;
|
||||||
impl Record for TAPECODE {
|
impl Record<Int2Array> for TAPECODE {
|
||||||
fn tag() -> u16 { RTAG_TAPECODE }
|
fn tag() -> u16 { RTAG_TAPECODE }
|
||||||
fn expected_size() -> usize { Some(2 * 6) }
|
fn expected_size() -> Option<u16> { Some(2 * 6) }
|
||||||
}
|
}
|
||||||
impl Int2Array for TAPECODE {}
|
|
||||||
|
|
||||||
pub struct STRCLASS {}
|
pub struct STRCLASS;
|
||||||
impl Record for STRCLASS {
|
impl Record<Int2> for STRCLASS {
|
||||||
fn tag() -> u16 { RTAG_STRCLASS }
|
fn tag() -> u16 { RTAG_STRCLASS }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for STRCLASS {}
|
|
||||||
|
|
||||||
pub struct RESERVED {}
|
pub struct RESERVED;
|
||||||
impl Record for RESERVED {
|
impl Record<Int2Array> for RESERVED {
|
||||||
fn tag() -> u16 { RTAG_RESERVED }
|
fn tag() -> u16 { RTAG_RESERVED }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2Array for RESERVED {}
|
|
||||||
|
|
||||||
pub struct FORMAT {}
|
pub struct FORMAT;
|
||||||
impl Record for FORMAT {
|
impl Record<Int2> for FORMAT {
|
||||||
fn tag() -> u16 { RTAG_FORMAT }
|
fn tag() -> u16 { RTAG_FORMAT }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for FORMAT {}
|
|
||||||
|
|
||||||
pub struct MASK {}
|
pub struct MASK;
|
||||||
impl Record for MASK {
|
impl Record<ASCII> for MASK {
|
||||||
fn tag() -> u16 { RTAG_MASK }
|
fn tag() -> u16 { RTAG_MASK }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for MASK {}
|
|
||||||
|
|
||||||
pub struct ENDMASKS {}
|
/// End of MASKS records
|
||||||
impl Record for ENDMASKS {
|
pub struct ENDMASKS;
|
||||||
// End of MASKS records
|
impl Record<Empty> for ENDMASKS {
|
||||||
fn tag() -> u16 { RTAG_ENDMASKS }
|
fn tag() -> u16 { RTAG_ENDMASKS }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LIBDIRSIZE {}
|
pub struct LIBDIRSIZE;
|
||||||
impl Record for LIBDIRSIZE {
|
impl Record<Int2> for LIBDIRSIZE {
|
||||||
fn tag() -> u16 { RTAG_LIBDIRSIZE }
|
fn tag() -> u16 { RTAG_LIBDIRSIZE }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for LIBDIRSIZE {}
|
|
||||||
|
|
||||||
pub struct SRFNAME {}
|
pub struct SRFNAME;
|
||||||
impl Record for SRFNAME {
|
impl Record<ASCII> for SRFNAME {
|
||||||
fn tag() -> u16 { RTAG_SRFNAME }
|
fn tag() -> u16 { RTAG_SRFNAME }
|
||||||
fn expected_size() -> usize { None }
|
fn expected_size() -> Option<u16> { None }
|
||||||
}
|
}
|
||||||
impl ASCII for SRFNAME {}
|
|
||||||
|
|
||||||
pub struct LIBSECUR {}
|
pub struct LIBSECUR;
|
||||||
impl Record for LIBSECUR {
|
impl Record<Int2> for LIBSECUR {
|
||||||
fn tag() -> u16 { RTAG_LIBSECUR }
|
fn tag() -> u16 { RTAG_LIBSECUR }
|
||||||
fn expected_size() -> usize { Some(2) }
|
fn expected_size() -> Option<u16> { Some(2) }
|
||||||
}
|
}
|
||||||
impl Int2 for LIBSECUR {}
|
|
||||||
|
|
||||||
pub struct BORDER {}
|
pub struct BORDER;
|
||||||
impl Record for BORDER {
|
impl Record<Empty> for BORDER {
|
||||||
fn tag() -> u16 { RTAG_BORDER }
|
fn tag() -> u16 { RTAG_BORDER }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SOFTFENCE {}
|
pub struct SOFTFENCE;
|
||||||
impl Record for SOFTFENCE {
|
impl Record<Empty> for SOFTFENCE {
|
||||||
fn tag() -> u16 { RTAG_SOFTFENCE }
|
fn tag() -> u16 { RTAG_SOFTFENCE }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HARDFENCE {}
|
pub struct HARDFENCE;
|
||||||
impl Record for HARDFENCE {
|
impl Record<Empty> for HARDFENCE {
|
||||||
fn tag() -> u16 { RTAG_HARDFENCE }
|
fn tag() -> u16 { RTAG_HARDFENCE }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SOFTWIRE {}
|
pub struct SOFTWIRE;
|
||||||
impl Record for SOFTWIRE {
|
impl Record<Empty> for SOFTWIRE {
|
||||||
fn tag() -> u16 { RTAG_SOFTWIRE }
|
fn tag() -> u16 { RTAG_SOFTWIRE }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HARDWIRE {}
|
pub struct HARDWIRE;
|
||||||
impl Record for HARDWIRE {
|
impl Record<Empty> for HARDWIRE {
|
||||||
fn tag() -> u16 { RTAG_HARDWIRE }
|
fn tag() -> u16 { RTAG_HARDWIRE }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PATHPORT {}
|
pub struct PATHPORT;
|
||||||
impl Record for PATHPORT {
|
impl Record<Empty> for PATHPORT {
|
||||||
fn tag() -> u16 { RTAG_PATHPORT }
|
fn tag() -> u16 { RTAG_PATHPORT }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NODEPORT {}
|
pub struct NODEPORT;
|
||||||
impl Record for NODEPORT {
|
impl Record<Empty> for NODEPORT {
|
||||||
fn tag() -> u16 { RTAG_NODEPORT }
|
fn tag() -> u16 { RTAG_NODEPORT }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct USERCONSTRAINT {}
|
pub struct USERCONSTRAINT;
|
||||||
impl Record for USERCONSTRAINT {
|
impl Record<Empty> for USERCONSTRAINT {
|
||||||
fn tag() -> u16 { RTAG_USERCONSTRAINT }
|
fn tag() -> u16 { RTAG_USERCONSTRAINT }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SPACERERROR {}
|
pub struct SPACERERROR;
|
||||||
impl Record for SPACERERROR {
|
impl Record<Empty> for SPACERERROR {
|
||||||
fn tag() -> u16 { RTAG_SPACERERROR }
|
fn tag() -> u16 { RTAG_SPACERERROR }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CONTACT {}
|
pub struct CONTACT;
|
||||||
impl Record for CONTACT {
|
impl Record<Empty> for CONTACT {
|
||||||
fn tag() -> u16 { RTAG_CONTACT }
|
fn tag() -> u16 { RTAG_CONTACT }
|
||||||
fn expected_size() -> usize { Some(0) }
|
fn expected_size() -> Option<u16> { Some(0) }
|
||||||
}
|
}
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
import numpy # type: ignore
|
|
||||||
from numpy.testing import assert_array_equal # type: ignore
|
|
||||||
|
|
||||||
from .basic import parse_bitarray, parse_int2, parse_int4, parse_real8, parse_ascii
|
|
||||||
from .basic import pack_bitarray, pack_int2, pack_int4, pack_real8, pack_ascii
|
|
||||||
from .basic import decode_real8, encode_real8
|
|
||||||
|
|
||||||
from .basic import KlamathError
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_bitarray():
|
|
||||||
assert(parse_bitarray(b'59') == 13625)
|
|
||||||
assert(parse_bitarray(b'\0\0') == 0)
|
|
||||||
assert(parse_bitarray(b'\xff\xff') == 65535)
|
|
||||||
|
|
||||||
# 4 bytes (too long)
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_bitarray(b'4321')
|
|
||||||
|
|
||||||
# empty data
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_bitarray(b'')
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_int2():
|
|
||||||
assert_array_equal(parse_int2(b'59\xff\xff\0\0'), (13625, -1, 0))
|
|
||||||
|
|
||||||
# odd length
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_int2(b'54321')
|
|
||||||
|
|
||||||
# empty data
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_int2(b'')
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_int4():
|
|
||||||
assert_array_equal(parse_int4(b'4321'), (875770417,))
|
|
||||||
|
|
||||||
# length % 4 != 0
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_int4(b'654321')
|
|
||||||
|
|
||||||
# empty data
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_int4(b'')
|
|
||||||
|
|
||||||
|
|
||||||
def test_decode_real8():
|
|
||||||
# zeroes
|
|
||||||
assert(decode_real8(numpy.array([0x0])) == 0)
|
|
||||||
assert(decode_real8(numpy.array([1<<63])) == 0) # negative
|
|
||||||
assert(decode_real8(numpy.array([0xff << 56])) == 0) # denormalized
|
|
||||||
|
|
||||||
assert(decode_real8(numpy.array([0x4110 << 48])) == 1.0)
|
|
||||||
assert(decode_real8(numpy.array([0xC120 << 48])) == -2.0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_real8():
|
|
||||||
packed = struct.pack('>3Q', 0x0, 0x4110_0000_0000_0000, 0xC120_0000_0000_0000)
|
|
||||||
assert_array_equal(parse_real8(packed), (0.0, 1.0, -2.0))
|
|
||||||
|
|
||||||
# length % 8 != 0
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_real8(b'0987654321')
|
|
||||||
|
|
||||||
# empty data
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_real8(b'')
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_ascii():
|
|
||||||
# empty data
|
|
||||||
with pytest.raises(KlamathError):
|
|
||||||
parse_ascii(b'')
|
|
||||||
|
|
||||||
assert(parse_ascii(b'12345') == b'12345')
|
|
||||||
assert(parse_ascii(b'12345\0') == b'12345') # strips trailing null byte
|
|
||||||
|
|
||||||
|
|
||||||
def test_pack_bitarray():
|
|
||||||
packed = pack_bitarray(321)
|
|
||||||
assert(len(packed) == 2)
|
|
||||||
assert(packed == struct.pack('>H', 321))
|
|
||||||
|
|
||||||
|
|
||||||
def test_pack_int2():
|
|
||||||
packed = pack_int2((3, 2, 1))
|
|
||||||
assert(len(packed) == 3*2)
|
|
||||||
assert(packed == struct.pack('>3h', 3, 2, 1))
|
|
||||||
assert(pack_int2([-3, 2, -1]) == struct.pack('>3h', -3, 2, -1))
|
|
||||||
|
|
||||||
|
|
||||||
def test_pack_int4():
|
|
||||||
packed = pack_int4((3, 2, 1))
|
|
||||||
assert(len(packed) == 3*4)
|
|
||||||
assert(packed == struct.pack('>3l', 3, 2, 1))
|
|
||||||
assert(pack_int4([-3, 2, -1]) == struct.pack('>3l', -3, 2, -1))
|
|
||||||
|
|
||||||
|
|
||||||
def test_encode_real8():
|
|
||||||
assert(encode_real8(numpy.array([0.0])) == 0)
|
|
||||||
arr = numpy.array((1.0, -2.0, 1e-9, 1e-3, 1e-12))
|
|
||||||
assert_array_equal(decode_real8(encode_real8(arr)), arr)
|
|
||||||
|
|
||||||
|
|
||||||
def test_pack_real8():
|
|
||||||
reals = (0, 1, -1, 0.5, 1e-9, 1e-3, 1e-12)
|
|
||||||
packed = pack_real8(reals)
|
|
||||||
assert(len(packed) == len(reals) * 8)
|
|
||||||
assert_array_equal(parse_real8(packed), reals)
|
|
||||||
|
|
||||||
|
|
||||||
def test_pack_ascii():
|
|
||||||
assert(pack_ascii(b'4321') == b'4321')
|
|
||||||
assert(pack_ascii(b'321') == b'321\0')
|
|
||||||
*/
|
|
Loading…
x
Reference in New Issue
Block a user