/* * Functionality for reading/writing elements (geometry, text labels, * structure references) and associated properties. */ //from .record import Record // use records::{BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF, DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE, LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING, STRANS, MAG, ANGLE, PROPATTR, PROPVALUE, ENDEL, BGNEXTN, ENDEXTN, SNAME, }; use records; use record::RecordHeader; use basic::{OWResult}; use std::collections::HashMap; use std::io::Write; use nom::IResult; pub fn read_properties(input: &[u8]) -> IResult<&[u8], HashMap::>> { /* * Read element properties. * * Assumes PROPATTR records have unique values. * Stops reading after consuming ENDEL record. * * Args: * stream: Stream to read from. * * Returns: * propattr: -> propvalue mapping */ let properties = HashMap{}; let (input, header) = RecordHeader::parse(input)?; while header.tag != ENDEL::tag() { if header.tag == PROPATTR::tag() { let (input, key) = PROPATTR::read_data(input, header.data_size)?; let (input, value) = PROPVALUE::read(input)?; assert!(!properties.contains_key(key), format!{"Duplicate property key: {}", key}); properties.insert(key, value); } let (input, header) = RecordHeader::parse(input)?; } Ok((input, properties)) } fn write_properties(ww: W, properties: &HashMap::>) -> OWResult { /* * Write element properties. * * This is does _not_ write the ENDEL record. * * Args: * stream: Stream to write to. */ let mut size = 0; for (key, value) in &properties { size += PROPATTR::write(ww, key)?; size += PROPVALUE::write(ww, value)?; } Ok(size) } trait Element { fn parse(input: &[u8]) -> Self; /* * Read from a stream to construct this object. * Consumes up to (and including) the ENDEL record. */ fn write(&self, ww: W) -> OWResult; /* * Write this element to a stream. * Finishes with an ENDEL record. */ } struct Reference { /* * Datastructure representing * an instance of a structure (SREF / structure reference) or * an array of instances (AREF / array reference). * Type is determined by the presence of the `colrow` tuple. * * Transforms are applied to each individual instance (_not_ * to the instance's origin location || array vectors). */ struct_name: Vec, // Name of the structure being referenced. invert_y: bool, // Whether to mirror the pattern (negate y-values / flip across x-axis). Default false. mag: f64, // Scaling factor (default 1) """ angle_deg: f64, // Rotation (degrees counterclockwise) xy: Vec, /* * (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0). * (For AREF) 3 locations: * [`offset`, * `offset + col_basis_vector * colrow[0]`, * `offset + row_basis_vector * colrow[1]`] * which define the first instance's offset and the array's basis vectors. * Note that many GDS implementations only support manhattan basis vectors, and some * assume a certain axis mapping (e.g. x->columns, y->rows) and "reinterpret" the * basis vectors to match it. */ colrow: Option<(i32, i32)>, // Number of columns and rows (AREF) || None (SREF) properties: HashMap::>, // Properties associated with this reference. } impl Element for Reference { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let mut invert_y = false; let mut mag = 1; let mut angle_deg = 0; let mut colrow = None; let (input, mut struct_name) = SNAME::skip_and_read(input)?; let (input, mut header) = RecordHeader::parse(input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_STRANS => {let (input, invert_y) = STRANS::read_data(input, header.data_size)?[0];}, records::RTAG_MAG => {let (input, mag) = MAG::read_data(input, header.data_size)?;}, records::RTAG_ANGLE => {let (input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, records::RTAG_COLROW => {let (input, colrow) = COLROW::read_data(input, header.data_size)?;}, _ => return Err(format!("Unexpected tag {:04x}", header.tag)), }; let (input, header) = RecordHeader::parse(input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, properties) = read_properties(input)?; Reference{ struct_name: struct_name, xy: xy, properties: properties, colrow: colrow, invert_y: invert_y, mag: mag, angle_deg: angle_deg } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += match self.colrow { None => SREF::write(ww)?, Some(_) => AREF::write(ww)?, }; size += SNAME::write(ww, self.struct_name)?; if self.angle_deg != 0 || self.mag != 1 || self.invert_y { size += STRANS::write(ww, (self.invert_y as u16) << 15)?; if self.mag != 1 { size += MAG::write(ww, self.mag)?; } if self.angle_deg !=0 { size += ANGLE::write(ww, self.angle_deg)?; } } if self.colrow.is_some() { size += COLROW::write(ww, self.colrow)?; } size += XY::write(ww, self.xy)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww, None)?; Ok(size) } } impl Reference { pub fn check(&self) { if self.colrow.is_some() { assert!(self.xy.len() != 6, format!("colrow is Some, so expected size-6 xy. Got {}", self.xy)); } else { assert!(self.xy.len() != 2, format!("Expected size-2 xy. Got {}", self.xy)); } } } struct Boundary { /* * Datastructure representing a Boundary element. */ layer: (i16, i16), // (layer, data_type) tuple xy: Vec, // Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,... properties: HashMap::>, // Properties for the element. } impl Element for Boundary { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = DATATYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; Boundary{ layer: (layer, dtype), xy: xy, properties: properties, } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += BOUNDARY::write(ww)?; size += LAYER::write(ww, self.layer.0)?; size += DATATYPE::write(ww, self.layer.1)?; size += XY::write(ww, self.xy)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww)?; Ok(size) } } struct Path { /* * Datastructure representing a Path element. * If `path_type < 4`, `extension` values are not written. * During read, `exension` defaults to (0, 0) even if unused. */ layer: (i16, i16), // (layer, data_type) tuple path_type: i16, // End-cap type (0: flush, 1: circle, 2: square, 4: custom) width: i16, // Path width extension: (i32, i32), // Extension when using path_type=4. Ignored otherwise. xy: Vec, // Path centerline coordinates. [x0, y0, x1, y1,...] properties: HashMap::>, //Properties for the element. } impl Element for Path { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let mut path_type = 0; let mut width = 0; let mut bgn_ext = 0; let mut end_ext = 0; let (input, mut layer) = LAYER::skip_and_read(input)?; let (input, mut dtype) = DATATYPE::read(input)?; let (input, mut header) = RecordHeader::parse(&input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_PATHTYPE => {let (input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, records::RTAG_WIDTH => {let (input, width) = WIDTH::read_data(input, header.data_size)?;}, records::RTAG_BGNEXTN => {let (input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;}, records::RTAG_ENDEXTN => {let (input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;}, _ => return Err(format!("Unexpected tag {:04x}", header.tag)), }; let (input, header) = RecordHeader::parse(&input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, properties) = read_properties(input)?; Path{ layer: (layer, dtype), xy: xy, properties: properties, extension: (bgn_ext, end_ext), path_type: path_type, width: width, } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += PATH::write(ww)?; size += LAYER::write(ww, self.layer[0])?; size += DATATYPE::write(ww, self.layer[1])?; if self.path_type != 0 { size += PATHTYPE::write(ww, self.path_type)?; } if self.width != 0 { size += WIDTH::write(ww, self.width)?; } if self.path_type < 4 { let (bgn_ext, end_ext) = self.extension; if bgn_ext != 0 { size += BGNEXTN::write(ww, bgn_ext)?; } if end_ext != 0 { size += ENDEXTN::write(ww, end_ext)?; } } size += XY::write(ww, self.xy)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww)?; Ok(size) } } struct GDSBox { /* * Datastructure representing a Box element. Rarely used. */ layer: (i16, i16), // (layer, box_type) tuple xy: Vec, // Box coordinates (5 pairs) properties: HashMap::>, // Properties for the element. } impl Element for GDSBox { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = BOXTYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; GDSBox{ layer: (layer, dtype), xy: xy, properties: properties, } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += BOX::write(ww)?; size += LAYER::write(ww, self.layer[0])?; size += BOXTYPE::write(ww, self.layer[1])?; size += XY::write(ww, self.xy)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww)?; Ok(size) } } struct Node { /* * Datastructure representing a Node element. Rarely used. */ layer: (i16, i16), // (layer, box_type) tuple xy: Vec, // 1-50 pairs of coordinates. properties: HashMap::>, // Properties for the element. } impl Element for Node { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = NODETYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; Node{ layer: (layer, dtype), xy: xy, properties: properties, } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += NODE::write(ww)?; size += LAYER::write(ww, self.layer[0])?; size += NODETYPE::write(ww, self.layer[1])?; size += XY::write(ww, self.xy)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww)?; Ok(size) } } struct Text { /* * Datastructure representing a text label. */ layer: (i16, i16), // (layer, node_type) tuple presentation: [bool; 16], /* * 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 */ path_type: i16, // Default 0 width: i32, // Default 0 invert_y: bool, // Vertical inversion. Default false. mag: f64, // Scaling factor. Default 1. angle_deg: f64, // Rotation (ccw). Default 0. xy: Vec, // Position (1 pair only) string: Vec, // Text content properties: HashMap::> // Properties for the element. } impl Element for Text { fn parse(input: &[u8]) -> IResult<&[u8], Self> { let mut path_type = 0; let mut presentation = 0; let mut invert_y = false; let mut width = 0; let mut mag = 1; let mut angle_deg = 0; let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = TEXTTYPE::read(input)?; let mut header = RecordHeader::parse(input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_PRESENTATION => {let (input, presentation) = PRESENTATION::read_data(input, header.data_size)?;}, records::RTAG_PATHTYPE => {let (input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, records::RTAG_WIDTH => {let (input, width) = WIDTH::read_data(input, header.data_size)?;}, records::RTAG_STRANS => { let (input, strans) = STRANS::read_data(input, header.data_size)?; invert_y = strans[0]; }, records::RTAG_MAG => {let (input, mag) = MAG::read_data(input, header.data_size)?;}, records::RTAG_ANGLE => {let (input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, _ => return Err(format!("Unexpected tag {:04x}", header.tag)), } let (input, header) = RecordHeader::parse(input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, string) = STRING::read(input)?; let (input, properties) = read_properties(input)?; Text{ layer: (layer, dtype), xy: xy, properties: properties, string: string, presentation: presentation, path_type: path_type, width: width, invert_y: invert_y, mag: mag, angle_deg: angle_deg, } } fn write(&self, ww: W) -> OWResult { let mut size = 0; size += TEXT::write(ww)?; size += LAYER::write(ww, self.layer[0])?; size += TEXTTYPE::write(ww, self.layer[1])?; if self.presentation != 0 { size += PRESENTATION::write(ww, self.presentation)?; } if self.path_type != 0 { size += PATHTYPE::write(ww, self.path_type)?; } if self.width != 0 { size += WIDTH::write(ww, self.width)? } if self.angle_deg != 0 || self.mag != 1 || self.invert_y { let strans = [false; 16]; strans[0] = self.invert_y; size += STRANS::write(ww, strans)?; if self.mag != 1 { size += MAG::write(ww, self.mag)?; } if self.angle_deg !=0 { size += ANGLE::write(ww, self.angle_deg)?; } } size += XY::write(ww, self.xy)?; size += STRING::write(ww, self.string)?; size += write_properties(ww, self.properties)?; size += ENDEL::write(ww)?; Ok(size) } }