/// /// Functionality for reading/writing elements (geometry, text labels, /// structure references) and associated properties. /// use crate::records::{ //BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF, DATATYPE, PATHTYPE, BOXTYPE, NODETYPE, TEXTTYPE, LAYER, XY, WIDTH, COLROW, PRESENTATION, STRING, STRANS, MAG, ANGLE, PROPATTR, PROPVALUE, ENDEL, BGNEXTN, ENDEXTN, SNAME, }; use crate::records; use crate::record::{RecordHeader, Record}; use crate::basic::{IResult, fail, take_bytes}; //OResult use std::string::String; use std::collections::HashMap; //use std::io::Write; use std::sync::Arc; use arrow::datatypes::{DataType, Field, Fields}; use arrow::array::{ StructBuilder, ListBuilder, StringBuilder, ArrayBuilder, Float64Builder, BooleanBuilder, Int32Builder, Int16Builder, UInt64Builder, UInt32Builder, UInt8Builder, StructArray, }; type DListBuilder = ListBuilder>; pub fn read_library(input: &[u8]) -> IResult { let input_size = input.len(); let property_t = DataType::Struct(Fields::from(vec![ Field::new("key", DataType::Int16, false), Field::new("value", DataType::Utf8, false), ])); let property_list_t = DataType::List(Arc::new( Field::new_list_field(property_t, false) )); let repetition_struct_t = DataType::Struct(Fields::from(vec![ Field::new("x0", DataType::Int32, false), Field::new("y0", DataType::Int32, false), Field::new("x1", DataType::Int32, false), Field::new("y1", DataType::Int32, false), Field::new("count0", DataType::Int16, false), Field::new("count1", DataType::Int16, false), ])); let ref_struct_t = DataType::Struct(Fields::from(vec![ Field::new("target", DataType::UInt32, false), Field::new("invert_y", DataType::Boolean, true), Field::new("mag", DataType::Float64, true), Field::new("angle_deg", DataType::Float64, true), Field::new("x", DataType::Int32, false), Field::new("y", DataType::Int32, false), Field::new("repetition", repetition_struct_t, true), Field::new("properties", property_list_t.clone(), true), ])); let text_struct_t = DataType::Struct(Fields::from(vec![ Field::new("layer", DataType::UInt16, false), Field::new("dtype", DataType::UInt16, false), Field::new("presentation_horiz", DataType::UInt8, true), Field::new("presentation_vert", DataType::UInt8, true), Field::new("presentation_font", DataType::UInt8, true), Field::new("path_type", DataType::Int16, true), Field::new("width", DataType::Int32, true), Field::new("invert_y", DataType::Boolean, true), Field::new("mag", DataType::Float64, true), Field::new("angle_deg", DataType::Float64, true), Field::new("x", DataType::Int32, false), Field::new("y", DataType::Int32, false), Field::new("string", DataType::Utf8, false), Field::new("properties", property_list_t.clone(), true), ])); let coords_t = DataType::List(Arc::new( Field::new_list_field(DataType::Int32, false) )); let boundary_struct_t = DataType::Struct(Fields::from(vec![ Field::new("layer", DataType::UInt16, false), Field::new("dtype", DataType::UInt16, false), Field::new("xy", coords_t.clone(), false), Field::new("properties", property_list_t.clone(), true), ])); let path_struct_t = DataType::Struct(Fields::from(vec![ Field::new("layer", DataType::UInt16, false), Field::new("dtype", DataType::UInt16, false), Field::new("path_type", DataType::Int16, false), Field::new("extension_start", DataType::Int32, true), Field::new("extension_end", DataType::Int32, true), Field::new("width", DataType::Int32, false), Field::new("xy", coords_t.clone(), false), Field::new("properties", property_list_t.clone(), true), ])); let boxnode_struct_t = DataType::Struct(Fields::from(vec![ Field::new("layer", DataType::UInt16, false), Field::new("dtype", DataType::UInt16, false), Field::new("xy", coords_t.clone(), false), Field::new("properties", property_list_t.clone(), true), ])); let ref_list_t = DataType::List(Arc::new( Field::new_list_field(ref_struct_t, false) )); let text_list_t = DataType::List(Arc::new( Field::new_list_field(text_struct_t, false) )); let boundary_list_t = DataType::List(Arc::new( Field::new_list_field(boundary_struct_t, false) )); let path_list_t = DataType::List(Arc::new( Field::new_list_field(path_struct_t, false) )); let boxnode_list_t = DataType::List(Arc::new( Field::new_list_field(boxnode_struct_t, false) )); let cell_struct_t = DataType::Struct(Fields::from(vec![ Field::new("id", DataType::UInt32, false), Field::new("file_offset", DataType::UInt64, false), Field::new("refs", ref_list_t, false), Field::new("boundaries", boundary_list_t, false), Field::new("paths", path_list_t, false), Field::new("nodes", boxnode_list_t.clone(), true), Field::new("boxes", boxnode_list_t.clone(), true), Field::new("texts", text_list_t, false), ])); let mut lib_builder = StructBuilder::from_fields(vec![ Field::new("cell_names", DataType::Utf8, false), Field::new("cells", cell_struct_t, false), ], 0, ); let cells_builder = lib_builder.field_builder::(0).unwrap(); let mut names = HashMap::::new(); let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_ENDLIB { (input, _) = take_bytes(input, header.data_size)?; if header.tag == records::RTAG_BGNSTR { let name_bytes; (input, name_bytes) = records::STRNAME::read(input)?; let name = String::from_utf8(name_bytes).unwrap(); let next_id = names.len(); let id = names.entry(name).or_insert(next_id.try_into().unwrap()); let position = input_size - input.len(); let cell_builder = cells_builder.values().as_any_mut().downcast_mut::().unwrap(); let id_builder = cell_builder.field_builder::(0).unwrap(); id_builder.append_value(*id); let offset_builder = cell_builder.field_builder::(1).unwrap(); offset_builder.append_value(position.try_into().unwrap()); (input, _) = read_elements(input, cell_builder, &mut names)?; cells_builder.append(true); } (input, header) = RecordHeader::read(input)?; } let mut ids: HashMap = names.into_iter().map(|(kk, vv)| (vv, kk)).collect(); let names_builder = lib_builder.field_builder::(1).unwrap(); for id in 0..ids.len() { names_builder.append_value(ids.remove(&id.try_into().unwrap()).unwrap()); } let lib = lib_builder.finish(); Ok((input, lib)) } pub fn read_elements<'a>(input: &'a [u8], cell_builder: &mut StructBuilder, names: &mut HashMap) -> IResult<'a, ()> { let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_ENDSTR { match header.tag { records::RTAG_BOUNDARY => {(input, _) = read_boundary(input, cell_builder)?;}, records::RTAG_PATH => {read_path(input, cell_builder)?;}, records::RTAG_NODE => {read_boxnode(input, cell_builder, header.tag)?;}, records::RTAG_BOX => {read_boxnode(input, cell_builder, header.tag)?;}, records::RTAG_TEXT => {read_text(input, cell_builder)?;}, records::RTAG_SREF => {read_ref(input, cell_builder, header.tag, names)?;}, records::RTAG_AREF => {read_ref(input, cell_builder, header.tag, names)?;}, _ => { // don't care, skip (input, _) = take_bytes(input, header.data_size)?; } } (input, header) = RecordHeader::read(input)?; } Ok((input, ())) } pub fn read_boundary<'a>(input: &'a [u8], cell_builder: &mut StructBuilder) -> IResult<'a, ()> { let boundaries_builder = cell_builder.field_builder::(3).unwrap(); let boundary_builder = boundaries_builder.values().as_any_mut().downcast_mut::().unwrap(); let (input, _) = records::BOUNDARY::read(input)?; let (input, layer) = LAYER::skip_and_read(input)?; let layer_builder = boundary_builder.field_builder::(0).unwrap(); layer_builder.append_value(layer); let (input, dtype) = DATATYPE::read(input)?; let dtype_builder = boundary_builder.field_builder::(1).unwrap(); dtype_builder.append_value(dtype); let xys_builder = boundary_builder.field_builder::(2).unwrap(); let xy_builder = xys_builder.values().as_any_mut().downcast_mut::().unwrap(); let (input, xy_iter) = XY::read(input)?; for xy in xy_iter { xy_builder.append_value(xy); } xys_builder.append(true); let props_builder = boundary_builder.field_builder::(3).unwrap(); let (input, ()) = read_properties(input, props_builder)?; boundary_builder.append(true); boundaries_builder.append(true); Ok((input, ())) } pub fn read_path<'a>(input: &'a [u8], cell_builder: &mut StructBuilder) -> IResult<'a, ()> { let paths_builder = cell_builder.field_builder::(4).unwrap(); let path_builder = paths_builder.values().as_any_mut().downcast_mut::().unwrap(); let (input, _) = records::PATH::read(input)?; let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = DATATYPE::read(input)?; let layer_builder = path_builder.field_builder::(0).unwrap(); layer_builder.append_value(layer); let dtype_builder = path_builder.field_builder::(1).unwrap(); dtype_builder.append_value(dtype); let mut path_type = None; let mut width = None; let mut bgn_ext = None; let mut end_ext = None; let (mut input, mut header) = RecordHeader::read(&input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_PATHTYPE => { let _path_type; (input, _path_type) = PATHTYPE::read_data(input, header.data_size)?; path_type = Some(_path_type); }, records::RTAG_WIDTH => { let _width; (input, _width) = WIDTH::read_data(input, header.data_size)?; width = Some(_width); }, records::RTAG_BGNEXTN => { let _bgn_ext; (input, _bgn_ext) = BGNEXTN::read_data(input, header.data_size)?; bgn_ext = Some(_bgn_ext); }, records::RTAG_ENDEXTN => { let _end_ext; (input, _end_ext) = ENDEXTN::read_data(input, header.data_size)?; end_ext = Some(_end_ext); }, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), }; (input, header) = RecordHeader::read(&input)?; } let path_type_builder = path_builder.field_builder::(2).unwrap(); path_type_builder.append_option(path_type); let ext0_builder = path_builder.field_builder::(3).unwrap(); ext0_builder.append_option(bgn_ext); let ext1_builder = path_builder.field_builder::(4).unwrap(); ext1_builder.append_option(end_ext); let width_builder = path_builder.field_builder::(5).unwrap(); width_builder.append_option(width); let xys_builder = path_builder.field_builder::(6).unwrap(); let (input, xy_iter) = XY::read(input)?; for xy in xy_iter { let xy_builder = xys_builder.values().as_any_mut().downcast_mut::().unwrap(); xy_builder.append_value(xy); } xys_builder.append(true); let props_builder = path_builder.field_builder::(7).unwrap(); let (input, ()) = read_properties(input, props_builder)?; path_builder.append(true); paths_builder.append(true); Ok((input, ())) } pub fn read_boxnode<'a>(input: &'a [u8], cell_builder: &mut StructBuilder, tag: u16) -> IResult<'a, ()> { let field_num = match tag { records::RTAG_NODE => 5, records::RTAG_BOX => 6, _ => return fail(input, format!("Unexpected tag {:04x}", tag)), }; let boxnodes_builder = cell_builder.field_builder::(field_num).unwrap(); let boxnode_builder = boxnodes_builder.values().as_any_mut().downcast_mut::().unwrap(); let (input, _) = match tag { records::RTAG_NODE => records::NODE::read(input)?, records::RTAG_BOX => records::BOX::read(input)?, _ => return fail(input, format!("Unexpected tag {:04x}", tag)), }; let layer_builder = boxnode_builder.field_builder::(0).unwrap(); let (input, layer) = LAYER::skip_and_read(input)?; layer_builder.append_value(layer); let (input, dtype) = match tag { records::RTAG_NODE => NODETYPE::read(input)?, records::RTAG_BOX => BOXTYPE::read(input)?, _ => return fail(input, format!("Unexpected tag {:04x}", tag)), }; let dtype_builder = boxnode_builder.field_builder::(1).unwrap(); dtype_builder.append_value(dtype); let xys_builder = boxnode_builder.field_builder::(2).unwrap(); let xy_builder = xys_builder.values().as_any_mut().downcast_mut::().unwrap(); let (input, xy_iter) = XY::read(input)?; for xy in xy_iter { xy_builder.append_value(xy); } xys_builder.append(true); let props_builder = boxnode_builder.field_builder::(3).unwrap(); let (input, ()) = read_properties(input, props_builder)?; boxnode_builder.append(true); boxnodes_builder.append(true); Ok((input, ())) } pub fn read_text<'a>(input: &'a [u8], cell_builder: &mut StructBuilder) -> IResult<'a, ()> { let texts_builder = cell_builder.field_builder::(7).unwrap(); let text_builder = texts_builder.values().as_any_mut().downcast_mut::().unwrap(); let mut path_type = None; let mut pres_hori = None; let mut pres_vert = None; let mut pres_font = None; let mut invert_y = None; let mut width = None; let mut mag = None; let mut angle_deg = None; let (input, layer) = LAYER::skip_and_read(input)?; let layer_builder = text_builder.field_builder::(0).unwrap(); layer_builder.append_value(layer); let (input, dtype) = TEXTTYPE::read(input)?; let dtype_builder = text_builder.field_builder::(1).unwrap(); dtype_builder.append_value(dtype); let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_XY { match header.tag { // TODO warn if repeat tags? records::RTAG_PRESENTATION => { let _presentation; (input, _presentation) = PRESENTATION::read_data(input, header.data_size)?; pres_hori = Some(_presentation[14] as u8 * 2 + _presentation[15] as u8); pres_vert = Some(_presentation[12] as u8 * 2 + _presentation[13] as u8); pres_font = Some(_presentation[10] as u8 * 2 + _presentation[11] as u8); }, records::RTAG_PATHTYPE => { let _path_type; (input, _path_type) = PATHTYPE::read_data(input, header.data_size)?; path_type = Some(_path_type); }, records::RTAG_WIDTH => { let _width; (input, _width) = WIDTH::read_data(input, header.data_size)?; width = Some(_width); }, records::RTAG_STRANS => { let strans; (input, strans) = STRANS::read_data(input, header.data_size)?; invert_y = Some(strans[0]); }, records::RTAG_MAG => { let _mag; (input, _mag) = MAG::read_data(input, header.data_size)?; mag = Some(_mag); }, records::RTAG_ANGLE => { let _angle_deg; (input, _angle_deg) = ANGLE::read_data(input, header.data_size)?; angle_deg = Some(_angle_deg); }, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), } (input, header) = RecordHeader::read(input)?; } let pres_hori_builder = text_builder.field_builder::(2).unwrap(); pres_hori_builder.append_option(pres_hori); let pres_vert_builder = text_builder.field_builder::(3).unwrap(); pres_vert_builder.append_option(pres_vert); let pres_font_builder = text_builder.field_builder::(4).unwrap(); pres_font_builder.append_option(pres_font); let path_type_builder = text_builder.field_builder::(5).unwrap(); path_type_builder.append_option(path_type); let width_builder = text_builder.field_builder::(6).unwrap(); width_builder.append_option(width); let inv_builder = text_builder.field_builder::(7).unwrap(); inv_builder.append_option(invert_y); let mag_builder = text_builder.field_builder::(8).unwrap(); mag_builder.append_option(mag); let angle_builder = text_builder.field_builder::(9).unwrap(); angle_builder.append_option(angle_deg); let (input, mut xy_iter) = XY::read(input)?; let x_builder = text_builder.field_builder::(10).unwrap(); x_builder.append_value(xy_iter.next().unwrap()); let y_builder = text_builder.field_builder::(11).unwrap(); y_builder.append_value(xy_iter.next().unwrap()); let (input, string_bytes) = STRING::read(input)?; let string = String::from_utf8(string_bytes).unwrap(); let string_builder = text_builder.field_builder::(12).unwrap(); string_builder.append_value(string); let props_builder = text_builder.field_builder::(13).unwrap(); let (input, ()) = read_properties(input, props_builder)?; text_builder.append(true); texts_builder.append(true); Ok((input, ())) } pub fn read_ref<'a>(input: &'a [u8], cell_builder: &mut StructBuilder, tag: u16, names: &mut HashMap) -> IResult<'a, ()> { let is_aref = tag == records::RTAG_AREF; let refs_builder = cell_builder.field_builder::(7).unwrap(); let ref_builder = refs_builder.values().as_any_mut().downcast_mut::().unwrap(); let mut invert_y = None; let mut mag = None; let mut angle_deg = None; let mut colrow = None; let (input, struct_name_bytes) = SNAME::skip_and_read(input)?; let struct_name = String::from_utf8(struct_name_bytes).unwrap(); let next_id = names.len(); let id = names.entry(struct_name).or_insert(next_id.try_into().unwrap()); let target_builder = ref_builder.field_builder::(0).unwrap(); target_builder.append_value(*id); let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_STRANS => { let strans; (input, strans) = STRANS::read_data(input, header.data_size)?; invert_y = Some(strans[0]); }, records::RTAG_MAG => { let _mag; (input, _mag) = MAG::read_data(input, header.data_size)?; mag = Some(_mag); }, records::RTAG_ANGLE => { let _angle_deg; (input, _angle_deg) = ANGLE::read_data(input, header.data_size)?; angle_deg = Some(_angle_deg); }, records::RTAG_COLROW => { let mut _colrow; (input, _colrow) = COLROW::read_data(input, header.data_size)?; colrow = Some((_colrow.next().unwrap(), _colrow.next().unwrap())); if !is_aref { return fail(input, "Got a COLROW record inside an SREF".to_string()); } }, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), }; (input, header) = RecordHeader::read(input)?; } let inv_builder = ref_builder.field_builder::(1).unwrap(); inv_builder.append_option(invert_y); let mag_builder = ref_builder.field_builder::(2).unwrap(); mag_builder.append_option(mag); let angle_builder = ref_builder.field_builder::(3).unwrap(); angle_builder.append_option(angle_deg); let (input, mut xy_iter) = XY::read_data(input, header.data_size)?; let x_builder = ref_builder.field_builder::(4).unwrap(); x_builder.append_value(xy_iter.next().unwrap()); let y_builder = ref_builder.field_builder::(5).unwrap(); y_builder.append_value(xy_iter.next().unwrap()); let rep_builder = ref_builder.field_builder::(6).unwrap(); if is_aref { let x0_builder = rep_builder.field_builder::(0).unwrap(); x0_builder.append_value(xy_iter.next().unwrap()); let y0_builder = rep_builder.field_builder::(1).unwrap(); y0_builder.append_value(xy_iter.next().unwrap()); let x1_builder = rep_builder.field_builder::(2).unwrap(); x1_builder.append_value(xy_iter.next().unwrap()); let y1_builder = rep_builder.field_builder::(3).unwrap(); y1_builder.append_value(xy_iter.next().unwrap()); match colrow { None => return fail(input, "AREF without COLROW before XY".to_string()), Some((count0, count1)) => { let count0_builder = rep_builder.field_builder::(4).unwrap(); count0_builder.append_value(count0); let count1_builder = rep_builder.field_builder::(5).unwrap(); count1_builder.append_value(count1); }, } } rep_builder.append(is_aref); let props_builder = ref_builder.field_builder::(7).unwrap(); let (input, ()) = read_properties(input, props_builder)?; ref_builder.append(true); refs_builder.append(true); Ok((input, ())) } /// /// Read element properties. /// /// Assumes PROPATTR records have unique values. /// Stops reading after consuming ENDEL record. /// /// Args: /// stream: Stream to read from. /// /// Returns: /// propattr: -> propvalue mapping /// pub fn read_properties<'a>(input: &'a [u8], props_builder: &mut DListBuilder) -> IResult<'a, ()> { let prop_builder = props_builder.values().as_any_mut().downcast_mut::().unwrap(); let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != ENDEL::tag() { if header.tag == PROPATTR::tag() { let key; let value_bytes; (input, key) = PROPATTR::read_data(input, header.data_size)?; (input, value_bytes) = PROPVALUE::read(input)?; let value = String::from_utf8(value_bytes).unwrap(); //assert!(!properties.contains_key(&key), "Duplicate property key: {}", key); let key_builder = prop_builder.field_builder::(0).unwrap(); key_builder.append_value(key); let val_builder = prop_builder.field_builder::(1).unwrap(); val_builder.append_value(value); prop_builder.append(true); } (input, header) = RecordHeader::read(input)?; } props_builder.append(true); Ok((input, ())) } /* /// /// Write element properties. /// /// This is does _not_ write the ENDEL record. /// /// Args: /// stream: Stream to write to. /// pub fn write_properties(ww: &mut W, properties: &HashMap::>) -> OResult { let mut size = 0; for (key, value) in properties { size += PROPATTR::write(ww, key)?; size += PROPVALUE::write(ww, value)?; } Ok(size) } pub trait Element { /// /// Read from a stream to construct this object. /// Consumes up to (and including) the ENDEL record. /// fn read(input: &[u8]) -> IResult where Self: Sized; /// /// Write this element to a stream. /// Finishes with an ENDEL record. /// fn write(&self, ww: &mut W) -> OResult; } /// /// Datastructure representing /// an instance of a structure (SREF / structure reference) or /// an array of instances (AREF / array reference). /// Type is determined by the presence of the `colrow` tuple. /// /// Transforms are applied to each individual instance (_not_ /// to the instance's origin location || array vectors). /// #[derive(Debug, Clone)] pub struct Reference { /// Name of the structure being referenced. struct_name: Vec, /// Whether to mirror the pattern (negate y-values / flip across x-axis). Default false. invert_y: bool, /// Scaling factor (default 1) mag: f64, /// Rotation (degrees counterclockwise) angle_deg: f64, /// (For SREF) Location in the parent structure corresponding to the instance's origin (0, 0). /// (For AREF) 3 locations: /// [`offset`, /// `offset + col_basis_vector * colrow[0]`, /// `offset + row_basis_vector * colrow[1]`] /// which define the first instance's offset and the array's basis vectors. /// Note that many GDS implementations only support manhattan basis vectors, and some /// assume a certain axis mapping (e.g. x->columns, y->rows) and "reinterpret" the /// basis vectors to match it. xy: Vec, /// Number of columns and rows (AREF) || None (SREF) colrow: Option<(i16, i16)>, /// Properties associated with this reference. properties: HashMap::>, } impl Element for Reference { fn read(input: &[u8]) -> IResult { let mut invert_y = false; let mut mag = 1.0; let mut angle_deg = 0.0; let mut colrow = None; let (input, struct_name) = SNAME::skip_and_read(input)?; let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_STRANS => { let result = STRANS::read_data(input, header.data_size)?; input = result.0; invert_y = result.1[0]; }, records::RTAG_MAG => {(input, mag) = MAG::read_data(input, header.data_size)?;}, records::RTAG_ANGLE => {(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, records::RTAG_COLROW => { let result = COLROW::read_data(input, header.data_size)?; input = result.0; colrow = Some((result.1[0], result.1[1])); }, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), }; (input, header) = RecordHeader::read(input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, properties) = read_properties(input)?; Ok((input, Reference{ struct_name: struct_name, xy: xy, properties: properties, colrow: colrow, invert_y: invert_y, mag: mag, angle_deg: angle_deg })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += match self.colrow { None => SREF::write(ww, &())?, Some(_) => AREF::write(ww, &())?, }; size += SNAME::write(ww, &self.struct_name)?; if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y { let strans = { let mut arr = [false; 16]; arr[0] = self.invert_y; arr }; size += STRANS::write(ww, &strans)?; if self.mag != 1.0 { size += MAG::write(ww, &self.mag)?; } if self.angle_deg != 0.0 { size += ANGLE::write(ww, &self.angle_deg)?; } } if let Some(cr) = self.colrow { size += COLROW::write(ww, &vec!{cr.0, cr.1})?; } size += XY::write(ww, &self.xy)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } impl Reference { pub fn check(&self) { if self.colrow.is_some() { assert!(self.xy.len() != 6, "colrow is Some, so expected size-6 xy. Got {:?}", self.xy); } else { assert!(self.xy.len() != 2, "Expected size-2 xy. Got {:?}", self.xy); } } } /// /// Datastructure representing a Boundary element. /// #[derive(Debug, Clone)] pub struct Boundary { /// (layer, data_type) tuple layer: (i16, i16), /// Ordered vertices of the shape. First and last points should be identical. Order x0, y0, x1,... xy: Vec, /// Properties for the element. properties: HashMap::>, } impl Element for Boundary { fn read(input: &[u8]) -> IResult { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = DATATYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; Ok((input, Boundary{ layer: (layer, dtype), xy: xy, properties: properties, })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += BOUNDARY::write(ww, &())?; size += LAYER::write(ww, &self.layer.0)?; size += DATATYPE::write(ww, &self.layer.1)?; size += XY::write(ww, &self.xy)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } /// /// Datastructure representing a Path element. /// /// If `path_type < 4`, `extension` values are not written. /// During read, `exension` defaults to (0, 0) even if unused. /// #[derive(Debug, Clone)] pub struct Path { /// (layer, data_type) tuple layer: (i16, i16), /// End-cap type (0: flush, 1: circle, 2: square, 4: custom) path_type: i16, /// Path width width: i32, /// Extension when using path_type=4. Ignored otherwise. extension: (i32, i32), /// Path centerline coordinates. [x0, y0, x1, y1,...] xy: Vec, /// Properties for the element. properties: HashMap::>, } impl Element for Path { fn read(input: &[u8]) -> IResult { let mut path_type = 0; let mut width = 0; let mut bgn_ext = 0; let mut end_ext = 0; let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = DATATYPE::read(input)?; let (mut input, mut header) = RecordHeader::read(&input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_PATHTYPE => {(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, records::RTAG_WIDTH => {(input, width) = WIDTH::read_data(input, header.data_size)?;}, records::RTAG_BGNEXTN => {(input, bgn_ext) = BGNEXTN::read_data(input, header.data_size)?;}, records::RTAG_ENDEXTN => {(input, end_ext) = ENDEXTN::read_data(input, header.data_size)?;}, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), }; (input, header) = RecordHeader::read(&input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, properties) = read_properties(input)?; Ok((input, Path{ layer: (layer, dtype), xy: xy, properties: properties, extension: (bgn_ext, end_ext), path_type: path_type, width: width, })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += PATH::write(ww, &())?; size += LAYER::write(ww, &self.layer.0)?; size += DATATYPE::write(ww, &self.layer.1)?; if self.path_type != 0 { size += PATHTYPE::write(ww, &self.path_type)?; } if self.width != 0 { size += WIDTH::write(ww, &self.width)?; } if self.path_type < 4 { let (bgn_ext, end_ext) = self.extension; if bgn_ext != 0 { size += BGNEXTN::write(ww, &bgn_ext)?; } if end_ext != 0 { size += ENDEXTN::write(ww, &end_ext)?; } } size += XY::write(ww, &self.xy)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } /// /// Datastructure representing a Box element. Rarely used. /// #[derive(Debug, Clone)] pub struct GDSBox { /// (layer, box_type) tuple layer: (i16, i16), /// Box coordinates (5 pairs) xy: Vec, /// Properties for the element. properties: HashMap::>, } impl Element for GDSBox { fn read(input: &[u8]) -> IResult { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = BOXTYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; Ok((input, GDSBox{ layer: (layer, dtype), xy: xy, properties: properties, })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += BOX::write(ww, &())?; size += LAYER::write(ww, &self.layer.0)?; size += BOXTYPE::write(ww, &self.layer.1)?; size += XY::write(ww, &self.xy)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } /// /// Datastructure representing a Node element. Rarely used. /// #[derive(Debug, Clone)] pub struct Node { /// (layer, box_type) tuple layer: (i16, i16), /// 1-50 pairs of coordinates. xy: Vec, /// Properties for the element. properties: HashMap::>, } impl Element for Node { fn read(input: &[u8]) -> IResult { let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = NODETYPE::read(input)?; let (input, xy) = XY::read(input)?; let (input, properties) = read_properties(input)?; Ok((input, Node{ layer: (layer, dtype), xy: xy, properties: properties, })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += NODE::write(ww, &())?; size += LAYER::write(ww, &self.layer.0)?; size += NODETYPE::write(ww, &self.layer.1)?; size += XY::write(ww, &self.xy)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } /// /// Datastructure representing a text label. /// #[derive(Debug, Clone)] pub struct Text { /// (layer, node_type) tuple layer: (i16, i16), /// Bit array. Default all zeros. /// bits 0-1: 00 left/01 center/10 right /// bits 2-3: 00 top/01 middle/10 bottom /// bits 4-5: font number presentation: [bool; 16], /// Default 0 path_type: i16, /// Default 0 width: i32, /// Vertical inversion. Default false. invert_y: bool, /// Scaling factor. Default 1. mag: f64, /// Rotation (ccw). Default 0. angle_deg: f64, /// Position (1 pair only) xy: Vec, /// Text content string: Vec, /// Properties for the element. properties: HashMap::> } impl Element for Text { fn read(input: &[u8]) -> IResult { let mut path_type = 0; let mut presentation = [false; 16]; let mut invert_y = false; let mut width = 0; let mut mag = 1.0; let mut angle_deg = 0.0; let (input, layer) = LAYER::skip_and_read(input)?; let (input, dtype) = TEXTTYPE::read(input)?; let (mut input, mut header) = RecordHeader::read(input)?; while header.tag != records::RTAG_XY { match header.tag { records::RTAG_PRESENTATION => {(input, presentation) = PRESENTATION::read_data(input, header.data_size)?;}, records::RTAG_PATHTYPE => {(input, path_type) = PATHTYPE::read_data(input, header.data_size)?;}, records::RTAG_WIDTH => {(input, width) = WIDTH::read_data(input, header.data_size)?;}, records::RTAG_STRANS => { let result = STRANS::read_data(input, header.data_size)?; input = result.0; invert_y = result.1[0]; }, records::RTAG_MAG => {(input, mag) = MAG::read_data(input, header.data_size)?;}, records::RTAG_ANGLE => {(input, angle_deg) = ANGLE::read_data(input, header.data_size)?;}, _ => return fail(input, format!("Unexpected tag {:04x}", header.tag)), } (input, header) = RecordHeader::read(input)?; } let (input, xy) = XY::read_data(input, header.data_size)?; let (input, string) = STRING::read(input)?; let (input, properties) = read_properties(input)?; Ok((input, Text{ layer: (layer, dtype), xy: xy, properties: properties, string: string, presentation: presentation, path_type: path_type, width: width, invert_y: invert_y, mag: mag, angle_deg: angle_deg, })) } fn write(&self, ww: &mut W) -> OResult { let mut size = 0; size += TEXT::write(ww, &())?; size += LAYER::write(ww, &self.layer.0)?; size += TEXTTYPE::write(ww, &self.layer.1)?; if self.presentation.iter().any(|&x| x) { size += PRESENTATION::write(ww, &self.presentation)?; } if self.path_type != 0 { size += PATHTYPE::write(ww, &self.path_type)?; } if self.width != 0 { size += WIDTH::write(ww, &self.width)? } if self.angle_deg != 0.0 || self.mag != 1.0 || self.invert_y { let strans = { let mut arr = [false; 16]; arr[0] = self.invert_y; arr }; size += STRANS::write(ww, &strans)?; if self.mag != 1.0 { size += MAG::write(ww, &self.mag)?; } if self.angle_deg != 0.0 { size += ANGLE::write(ww, &self.angle_deg)?; } } size += XY::write(ww, &self.xy)?; size += STRING::write(ww, &self.string)?; size += write_properties(ww, &self.properties)?; size += ENDEL::write(ww, &())?; Ok(size) } } */