gds/
write.rs

1//! Utilities for byte-encoding and writing.
2
3// Local imports
4use super::*;
5
6/// A GDS writer.
7pub struct GdsWriter<'wr> {
8    /// Write destination.
9    dest: Box<dyn Write + 'wr>,
10}
11
12impl<'wr> GdsWriter<'wr> {
13    /// Creates new [GdsWriter] with destination file `fname`.
14    pub fn open(fname: impl AsRef<Path>) -> GdsResult<Self> {
15        let file = BufWriter::new(File::create(fname)?);
16        Ok(Self::new(file))
17    }
18
19    /// Creates a new [GdsWriter] to destination `dest`.
20    pub fn new(dest: impl Write + 'wr) -> Self {
21        Self {
22            dest: Box::new(dest),
23        }
24    }
25
26    /// Writes [GdsLibrary] `lib` to our destination.
27    pub fn write_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
28        // `write_lib` is our typicaly entry point when writing to file.
29        // It quickly dispatches most behavior off to our implementation of the [Encode] trait.
30        self.encode_lib(lib)
31    }
32
33    /// Helper to write a sequence of [GdsRecord] references.
34    fn write_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> {
35        for r in records {
36            self.write_record(r)?;
37        }
38        Ok(())
39    }
40
41    /// Encodes into bytes and write ontos `dest`.
42    fn write_record(&mut self, record: &GdsRecord) -> GdsResult<()> {
43        // This is split in two parts - header and data - largely to ease handling the variety of datatypes
44        self.write_record_header(record)?;
45        self.write_record_content(record)?;
46        Ok(())
47    }
48
49    fn write_record_header(&mut self, record: &GdsRecord) -> GdsResult<()> {
50        // A quick closure for GDS's "even-lengths-only allowed" strings
51        let gds_strlen = |s: &str| -> usize { s.len() + s.len() % 2 };
52        // First grab the header info: RecordType, DataType, and length
53        use GdsDataType::{BitArray, F64, I16, I32, NoData, Str};
54        let (rtype, dtype, len) = match record {
55            // Library-Level Records
56            GdsRecord::Header { .. } => (GdsRecordType::Header, I16, 2),
57            GdsRecord::BgnLib { .. } => (GdsRecordType::BgnLib, I16, 24),
58            GdsRecord::LibName(s) => (GdsRecordType::LibName, Str, gds_strlen(s)),
59            GdsRecord::Units(_, _) => (GdsRecordType::Units, F64, 16),
60            GdsRecord::EndLib => (GdsRecordType::EndLib, NoData, 0),
61
62            // Structure (Cell) Level Records
63            GdsRecord::BgnStruct { .. } => (GdsRecordType::BgnStruct, I16, 24),
64            GdsRecord::StructName(s) => (GdsRecordType::StructName, Str, gds_strlen(s)),
65            GdsRecord::StructRefName(s) => (GdsRecordType::StructRefName, Str, gds_strlen(s)),
66            GdsRecord::EndStruct => (GdsRecordType::EndStruct, NoData, 0),
67
68            // Element-Level Records
69            GdsRecord::Boundary => (GdsRecordType::Boundary, NoData, 0),
70            GdsRecord::Path => (GdsRecordType::Path, NoData, 0),
71            GdsRecord::StructRef => (GdsRecordType::StructRef, NoData, 0),
72            GdsRecord::ArrayRef => (GdsRecordType::ArrayRef, NoData, 0),
73            GdsRecord::Text => (GdsRecordType::Text, NoData, 0),
74            GdsRecord::Layer(_) => (GdsRecordType::Layer, I16, 2),
75            GdsRecord::DataType(_) => (GdsRecordType::DataType, I16, 2),
76            GdsRecord::Width(_) => (GdsRecordType::Width, I32, 4),
77            GdsRecord::Xy(d) => (GdsRecordType::Xy, I32, 4 * d.len()),
78            GdsRecord::EndElement => (GdsRecordType::EndElement, NoData, 0),
79
80            // More (less well-categorized here) record-types
81            GdsRecord::ColRow { .. } => (GdsRecordType::ColRow, I16, 4),
82            GdsRecord::Node => (GdsRecordType::Node, NoData, 0),
83            GdsRecord::TextType(_) => (GdsRecordType::TextType, I16, 2),
84            GdsRecord::Presentation(_, _) => (GdsRecordType::Presentation, BitArray, 2),
85            GdsRecord::String(s) => (GdsRecordType::String, Str, gds_strlen(s)),
86            GdsRecord::Strans(_, _) => (GdsRecordType::Strans, BitArray, 2),
87            GdsRecord::Mag(_) => (GdsRecordType::Mag, F64, 8),
88            GdsRecord::Angle(_) => (GdsRecordType::Angle, F64, 8),
89            GdsRecord::RefLibs(s) => (GdsRecordType::RefLibs, Str, gds_strlen(s)),
90            GdsRecord::Fonts(s) => (GdsRecordType::Fonts, Str, gds_strlen(s)),
91            GdsRecord::PathType(_) => (GdsRecordType::PathType, I16, 2),
92            GdsRecord::Generations(_) => (GdsRecordType::Generations, I16, 2),
93            GdsRecord::AttrTable(s) => (GdsRecordType::AttrTable, Str, gds_strlen(s)),
94            GdsRecord::ElemFlags(_, _) => (GdsRecordType::ElemFlags, BitArray, 2),
95            GdsRecord::Nodetype(_) => (GdsRecordType::Nodetype, I16, 2),
96            GdsRecord::PropAttr(_) => (GdsRecordType::PropAttr, I16, 2),
97            GdsRecord::PropValue(s) => (GdsRecordType::PropValue, Str, gds_strlen(s)),
98            GdsRecord::Box => (GdsRecordType::Box, NoData, 0),
99            GdsRecord::BoxType(_) => (GdsRecordType::BoxType, I16, 2),
100            GdsRecord::Plex(_) => (GdsRecordType::Plex, I32, 4),
101            GdsRecord::BeginExtn(_) => (GdsRecordType::BeginExtn, I32, 4),
102            GdsRecord::EndExtn(_) => (GdsRecordType::EndExtn, I32, 4),
103            GdsRecord::TapeNum(_) => (GdsRecordType::TapeNum, I16, 2),
104            GdsRecord::TapeCode(_) => (GdsRecordType::TapeCode, I16, 12),
105            GdsRecord::Format(_) => (GdsRecordType::Format, I16, 2),
106            GdsRecord::Mask(s) => (GdsRecordType::Mask, Str, gds_strlen(s)),
107            GdsRecord::EndMasks => (GdsRecordType::EndMasks, NoData, 0),
108            GdsRecord::LibDirSize(_) => (GdsRecordType::LibDirSize, I16, 2),
109            GdsRecord::SrfName(s) => (GdsRecordType::SrfName, Str, gds_strlen(s)),
110            GdsRecord::LibSecur(_) => (GdsRecordType::LibSecur, I16, 2),
111        };
112        // Send those header-bytes to the writer.
113        // Include the four header bytes in total-length.
114        match u16::try_from(len + 4) {
115            Ok(val) => self.dest.write_u16::<BigEndian>(val)?,
116            Err(_) => return Err(GdsError::RecordLen(len)),
117        };
118        self.dest.write_u8(rtype as u8)?;
119        self.dest.write_u8(dtype as u8)?;
120        Ok(())
121    }
122
123    fn write_record_content(&mut self, record: &GdsRecord) -> GdsResult<()> {
124        // Now write the data portion
125        // This section is generally organized by DataType
126        match record {
127            // NoData
128            GdsRecord::EndLib
129            | GdsRecord::EndStruct
130            | GdsRecord::Boundary
131            | GdsRecord::Path
132            | GdsRecord::StructRef
133            | GdsRecord::ArrayRef
134            | GdsRecord::Text
135            | GdsRecord::EndElement
136            | GdsRecord::Node
137            | GdsRecord::Box
138            | GdsRecord::EndMasks => (),
139
140            // BitArrays
141            GdsRecord::Presentation(d0, d1)
142            | GdsRecord::Strans(d0, d1)
143            | GdsRecord::ElemFlags(d0, d1) => {
144                self.dest.write_u8(*d0)?;
145                self.dest.write_u8(*d1)?;
146            }
147            // Single I16s
148            GdsRecord::Header { version: d }
149            | GdsRecord::Layer(d)
150            | GdsRecord::DataType(d)
151            | GdsRecord::TextType(d)
152            | GdsRecord::PathType(d)
153            | GdsRecord::Generations(d)
154            | GdsRecord::Nodetype(d)
155            | GdsRecord::PropAttr(d)
156            | GdsRecord::BoxType(d)
157            | GdsRecord::TapeNum(d)
158            | GdsRecord::Format(d)
159            | GdsRecord::LibDirSize(d)
160            | GdsRecord::LibSecur(d) => self.dest.write_i16::<BigEndian>(*d)?,
161
162            // Single I32s
163            GdsRecord::Width(d)
164            | GdsRecord::Plex(d)
165            | GdsRecord::BeginExtn(d)
166            | GdsRecord::EndExtn(d) => self.dest.write_i32::<BigEndian>(*d)?,
167            // Single F64s
168            GdsRecord::Mag(d) | GdsRecord::Angle(d) => {
169                self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d))?
170            }
171            // "Structs"
172            GdsRecord::Units(d0, d1) => {
173                self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d0))?;
174                self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d1))?;
175            }
176            GdsRecord::ColRow { cols, rows } => {
177                self.dest.write_i16::<BigEndian>(*cols)?;
178                self.dest.write_i16::<BigEndian>(*rows)?;
179            }
180            // Fixed-Length Arrays
181            GdsRecord::BgnLib { dates: d } | GdsRecord::BgnStruct { dates: d } => {
182                for val in d.iter() {
183                    self.dest.write_i16::<BigEndian>(*val)?;
184                }
185            }
186            // Vectors
187            GdsRecord::TapeCode(d) => {
188                for val in d.iter() {
189                    self.dest.write_i16::<BigEndian>(*val)?;
190                }
191            }
192            GdsRecord::Xy(d) => {
193                for val in d.iter() {
194                    self.dest.write_i32::<BigEndian>(*val)?;
195                }
196            }
197            // Strings
198            GdsRecord::LibName(s)
199            | GdsRecord::StructName(s)
200            | GdsRecord::StructRefName(s)
201            | GdsRecord::String(s)
202            | GdsRecord::RefLibs(s)
203            | GdsRecord::Fonts(s)
204            | GdsRecord::AttrTable(s)
205            | GdsRecord::PropValue(s)
206            | GdsRecord::Mask(s)
207            | GdsRecord::SrfName(s) => {
208                for b in s.as_bytes() {
209                    self.dest.write_u8(*b)?;
210                }
211                if s.len() % 2 != 0 {
212                    // Pad odd-length strings with a zero-valued byte
213                    self.dest.write_u8(0x00)?;
214                }
215            }
216        };
217        Ok(())
218    }
219}
220
221/// [Encode] implementation for [GdsWriter].
222///
223/// Dispatches record-level calls back to the `write_record(s)` methods.
224impl Encode for GdsWriter<'_> {
225    fn encode_record(&mut self, record: GdsRecord) -> GdsResult<()> {
226        self.write_record(&record)
227    }
228    fn encode_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> {
229        self.write_records(records)
230    }
231}
232
233/// An object that can be encoded in a GDS file.
234///
235/// Performs conversion of each element in the [GdsLibrary] tree to [GdsRecord]s,
236/// each passed to its `encode_record` (singular) or `encode_records` (plural) methods.
237/// Each type is encoded in the order recommended by the GDSII spec.
238///
239/// Most of the behavior required of [GdsWriter] is implemented in this trait.
240/// It is broken out into a trait to enable alternate "destinations" for the encoded records,
241/// such as collecting them in a [Vec] as done by [GdsRecordList].
242trait Encode {
243    // Virtual / Required Methods
244    /// Encodes a single [GdsRecord].
245    fn encode_record(&mut self, record: GdsRecord) -> GdsResult<()>;
246    /// Encodes an array of [GdsRecord]s.
247    fn encode_records(&mut self, records: &[GdsRecord]) -> GdsResult<()>;
248
249    // Default Methods
250    /// Encodes a [GdsLibrary].
251    fn encode_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
252        // Write our header content
253        self.encode_records(&[
254            GdsRecord::Header {
255                version: lib.version,
256            },
257            GdsRecord::BgnLib {
258                dates: lib.dates.encode().to_vec(),
259            },
260            GdsRecord::LibName(lib.name.clone()),
261            GdsRecord::Units(lib.units.0, lib.units.1),
262        ])?;
263        // Write all of our Structs/Cells
264        for strukt in lib.structs.iter() {
265            self.encode_struct(strukt)?;
266        }
267        // And finally, the library terminator
268        self.encode_record(GdsRecord::EndLib)?;
269        Ok(())
270    }
271
272    /// Encodes a [GdsStruct].
273    fn encode_struct(&mut self, strukt: &GdsStruct) -> GdsResult<()> {
274        // Write the header content
275        self.encode_records(&[
276            GdsRecord::BgnStruct {
277                dates: strukt.dates.encode().to_vec(),
278            },
279            GdsRecord::StructName(strukt.name.clone()),
280        ])?;
281        // Write each of our elements
282        for elem in strukt.elems.iter() {
283            self.encode_element(elem)?;
284        }
285        // And its terminator
286        self.encode_record(GdsRecord::EndStruct)?;
287        Ok(())
288    }
289
290    /// Encodes a [GdsElement], dispatching across its variants.
291    fn encode_element(&mut self, elem: &GdsElement) -> GdsResult<()> {
292        use GdsElement::*;
293        match elem {
294            GdsBoundary(e) => self.encode_boundary(e)?,
295            GdsPath(e) => self.encode_path(e)?,
296            GdsStructRef(e) => self.encode_struct_ref(e)?,
297            GdsArrayRef(e) => self.encode_array_ref(e)?,
298            GdsTextElem(e) => self.encode_text_elem(e)?,
299            GdsNode(e) => self.encode_node(e)?,
300            GdsBox(e) => self.encode_box(e)?,
301        };
302        Ok(())
303    }
304
305    /// Encodes a [GdsPath].
306    fn encode_path(&mut self, path: &GdsPath) -> GdsResult<()> {
307        self.encode_record(GdsRecord::Path)?;
308        if let Some(ref e) = path.elflags {
309            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
310        }
311        if let Some(ref e) = path.plex {
312            self.encode_record(GdsRecord::Plex(e.0))?;
313        }
314        self.encode_record(GdsRecord::Layer(path.layer))?;
315        self.encode_record(GdsRecord::DataType(path.datatype))?;
316        if let Some(ref e) = path.path_type {
317            self.encode_record(GdsRecord::PathType(*e))?;
318        }
319        if let Some(ref e) = path.width {
320            self.encode_record(GdsRecord::Width(*e))?;
321        }
322        if let Some(ref e) = path.begin_extn {
323            self.encode_record(GdsRecord::BeginExtn(*e))?;
324        }
325        if let Some(ref e) = path.end_extn {
326            self.encode_record(GdsRecord::EndExtn(*e))?;
327        }
328        self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&path.xy)))?;
329        for prop in path.properties.iter() {
330            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
331            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
332        }
333        self.encode_record(GdsRecord::EndElement)?;
334        Ok(())
335    }
336
337    /// Encodes a [GdsBoundary].
338    fn encode_boundary(&mut self, boundary: &GdsBoundary) -> GdsResult<()> {
339        self.encode_record(GdsRecord::Boundary)?;
340        if let Some(ref e) = boundary.elflags {
341            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
342        }
343        if let Some(ref e) = boundary.plex {
344            self.encode_record(GdsRecord::Plex(e.0))?;
345        }
346        self.encode_record(GdsRecord::Layer(boundary.layer))?;
347        self.encode_record(GdsRecord::DataType(boundary.datatype))?;
348        self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&boundary.xy)))?;
349        for prop in boundary.properties.iter() {
350            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
351            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
352        }
353        self.encode_record(GdsRecord::EndElement)?;
354        Ok(())
355    }
356
357    /// Encodes a [GdsStructRef].
358    fn encode_struct_ref(&mut self, sref: &GdsStructRef) -> GdsResult<()> {
359        self.encode_record(GdsRecord::StructRef)?;
360        if let Some(ref e) = sref.elflags {
361            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
362        }
363        if let Some(ref e) = sref.plex {
364            self.encode_record(GdsRecord::Plex(e.0))?;
365        }
366        self.encode_record(GdsRecord::StructRefName(sref.name.clone()))?;
367        if let Some(ref e) = sref.strans {
368            self.encode_strans(e)?;
369        }
370        self.encode_record(GdsRecord::Xy(GdsPoint::flatten(&sref.xy)))?;
371        for prop in sref.properties.iter() {
372            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
373            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
374        }
375        self.encode_record(GdsRecord::EndElement)?;
376        Ok(())
377    }
378
379    /// Encodes a [GdsArrayRef].
380    fn encode_array_ref(&mut self, aref: &GdsArrayRef) -> GdsResult<()> {
381        self.encode_record(GdsRecord::ArrayRef)?;
382        if let Some(ref e) = aref.elflags {
383            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
384        }
385        if let Some(ref e) = aref.plex {
386            self.encode_record(GdsRecord::Plex(e.0))?;
387        }
388        self.encode_record(GdsRecord::StructRefName(aref.name.clone()))?;
389        if let Some(ref e) = aref.strans {
390            self.encode_strans(e)?;
391        }
392        self.encode_record(GdsRecord::ColRow {
393            cols: aref.cols,
394            rows: aref.rows,
395        })?;
396        let mut xy = GdsPoint::flatten(&aref.xy[0]);
397        xy.extend(GdsPoint::flatten(&aref.xy[1]));
398        xy.extend(GdsPoint::flatten(&aref.xy[2]));
399        self.encode_record(GdsRecord::Xy(xy))?;
400        for prop in aref.properties.iter() {
401            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
402            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
403        }
404        self.encode_record(GdsRecord::EndElement)?;
405        Ok(())
406    }
407
408    /// Encodes a [GdsTextElem].
409    fn encode_text_elem(&mut self, text: &GdsTextElem) -> GdsResult<()> {
410        self.encode_record(GdsRecord::Text)?;
411        if let Some(ref e) = text.elflags {
412            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
413        }
414        if let Some(ref e) = text.plex {
415            self.encode_record(GdsRecord::Plex(e.0))?;
416        }
417        self.encode_record(GdsRecord::Layer(text.layer))?;
418        self.encode_record(GdsRecord::TextType(text.texttype))?;
419        if let Some(ref e) = text.presentation {
420            self.encode_record(GdsRecord::Presentation(e.0, e.1))?;
421        }
422        if let Some(ref e) = text.path_type {
423            self.encode_record(GdsRecord::PathType(*e))?;
424        }
425        if let Some(ref e) = text.width {
426            self.encode_record(GdsRecord::Width(*e))?;
427        }
428        if let Some(ref e) = text.strans {
429            self.encode_strans(e)?;
430        }
431        self.encode_record(GdsRecord::Xy(GdsPoint::flatten(&text.xy)))?;
432        self.encode_record(GdsRecord::String(text.string.clone()))?;
433        for prop in text.properties.iter() {
434            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
435            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
436        }
437        self.encode_record(GdsRecord::EndElement)?;
438        Ok(())
439    }
440
441    /// Encodes a [GdsNode].
442    fn encode_node(&mut self, node: &GdsNode) -> GdsResult<()> {
443        self.encode_record(GdsRecord::Node)?;
444        if let Some(ref e) = node.elflags {
445            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
446        }
447        if let Some(ref e) = node.plex {
448            self.encode_record(GdsRecord::Plex(e.0))?;
449        }
450        self.encode_record(GdsRecord::Layer(node.layer))?;
451        self.encode_record(GdsRecord::Nodetype(node.nodetype))?;
452        self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&node.xy)))?;
453        for prop in node.properties.iter() {
454            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
455            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
456        }
457        self.encode_record(GdsRecord::EndElement)?;
458        Ok(())
459    }
460
461    /// Encodes a [GdsBox].
462    fn encode_box(&mut self, box_: &GdsBox) -> GdsResult<()> {
463        self.encode_record(GdsRecord::Box)?;
464        if let Some(ref e) = box_.elflags {
465            self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
466        }
467        if let Some(ref e) = box_.plex {
468            self.encode_record(GdsRecord::Plex(e.0))?;
469        }
470        self.encode_record(GdsRecord::Layer(box_.layer))?;
471        self.encode_record(GdsRecord::BoxType(box_.boxtype))?;
472        self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(box_.xy.as_ref())))?;
473        for prop in box_.properties.iter() {
474            self.encode_record(GdsRecord::PropAttr(prop.attr))?;
475            self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
476        }
477        self.encode_record(GdsRecord::EndElement)?;
478        Ok(())
479    }
480
481    /// Encodes a [GdsStrans].
482    fn encode_strans(&mut self, strans: &GdsStrans) -> GdsResult<()> {
483        self.encode_record(GdsRecord::Strans(
484            (strans.reflected as u8) << 7,
485            ((strans.abs_mag as u8) << 2) | ((strans.abs_angle as u8) << 1),
486        ))?;
487        if let Some(ref e) = strans.mag {
488            self.encode_record(GdsRecord::Mag(*e))?;
489        }
490        if let Some(ref e) = strans.angle {
491            self.encode_record(GdsRecord::Angle(*e))?;
492        }
493        Ok(())
494    }
495}
496
497impl GdsDateTimes {
498    /// Encodes a date-time in GDSII's vector of i16's format.
499    pub fn encode(&self) -> [i16; 12] {
500        [
501            self.modified.date().year() as i16,
502            self.modified.date().month() as i16,
503            self.modified.date().day() as i16,
504            self.modified.time().hour() as i16,
505            self.modified.time().minute() as i16,
506            self.modified.time().second() as i16,
507            self.accessed.date().year() as i16,
508            self.accessed.date().month() as i16,
509            self.accessed.date().day() as i16,
510            self.accessed.time().hour() as i16,
511            self.accessed.time().minute() as i16,
512            self.accessed.time().second() as i16,
513        ]
514    }
515}