gds/
lib.rs

1//! A library for parsing and writing GDSII files.
2//!
3//! GDSII is the IC industry's de facto standard for storing and sharing layout data.
4//! `gds` is a crate for reading and creating GDSII data based on [Gds21](https://github.com/dan-fritchman/Layout21/tree/main/gds21) and similar to libraries such as [gdstk](https://github.com/heitzmann/gdstk) and its predecessor [gdspy](https://github.com/heitzmann/gdspy).
5//! Reading and generating GDSII-format data are primary goals;
6//! offering ease-of-use functionality for more elaborate manipulations of GDS data is not.
7//!
8//! Layout data is represented in three primary forms:
9//!
10//! * A short tree with three layers:
11//!   * The root is a [`GdsLibrary`], which primarily consists of a set of cells ([`GdsStruct`]s), and secondarily a set of metadata.
12//!     Each [`GdsLibrary`] is a universe unto itself, in that it has no mechanisms for comprehending layout cells or data defined outside itself.
13//!     On-disk each [`GdsLibrary`] is typically paired one-to-one with a `.gds` file.
14//!   * Libraries consist of cell definitions AKA [`GdsStruct`]s, which define each layout cell (or module, or "struct" in GDSII terms).
15//!   * Cells consist of [`GdsElement`]s, an enumeration which includes individual polygons ([`GdsBoundary`]),
16//!     instances of other layout cells ([`GdsStructRef`]), text ([`GdsTextElem`]), and a few other geometric elements.
17//! * For storage on disk, the [`GdsLibrary`] tree is flattened to a series of [`GdsRecord`]s.
18//!   These records indicate the beginning, end, and content of each tree-node.
19//!   Detailed descriptions of these records comprise the majority of the GDSII spec.
20//! * Records are stored on-disk in binary form as detailed in the GDSII spec.
21//!   Each includes a record-type header, datatype, length field, and optional additional content.
22//!   These raw-bytes are never stored by Gds21, only generated and consumed on their way into and out of [`Read`] and [`Write`] objects (typically [`File`]s).
23//!
24//!
25//! ### Usage
26//!
27//! Loading a [`GdsLibrary`] from disk:
28//!
29//! ```skip
30//! let lib = GdsLibrary::load("sample.gds")?;
31//! ```
32//!
33//! Creating a new and empty [`GdsLibrary`], and adding a [`GdsStruct`] cell-definition:
34//!
35//! ```rust
36//! use gds::{GdsLibrary, GdsStruct};
37//! let mut lib = GdsLibrary::new("mylib");
38//! lib.structs.push(GdsStruct::new("mycell"));
39//! ```
40//!
41//! Saving a [`GdsLibrary`] to disk:
42//!
43//! ```skip
44//! lib.save("mylib.gds");
45//! ```
46//!
47//! ### Serialization
48//!
49//! Each element in Gds21's [`GdsLibrary`] tree is [`serde`]-serializable.
50//! GDSII data can be straightforwardly serialized in any serde-supported format.
51//! Examples:
52//!
53//! ```
54//! let lib = gds::GdsLibrary::new("mylib");
55//! let json = serde_json::to_string(&lib);
56//! let yaml = serde_yaml::to_string(&lib);
57//! let toml = toml::to_string(&lib);
58//! ```
59//!
60//! Gds21 includes built-in support for a subset of serde-formats via its [`SerializationFormat`] enumeration,
61//! and support for directly reading and writing files in each format via its accompanying [`SerdeFile`] trait.
62//! Example using [`SerializationFormat::Yaml`]:
63//!
64//! ```skip
65//! use gds::SerializationFormat::Yaml;
66//! let lib = gds::GdsLibrary::new("mylib");
67//!
68//! // Write to YAML-format file
69//! Yaml.save(&lib, "mylib.gds.yaml")?;
70//! // And read back from file
71//! let lib2: gds::GdsLibrary = Yaml.open("mylib.gds.yaml")?;
72//! ```
73//!
74//! Note these text-based representations will generally be substantially larger than binary GDSII data.
75#![warn(missing_docs)]
76
77#[doc(hidden)]
78mod read;
79mod ser;
80#[cfg(test)]
81mod tests;
82#[doc(hidden)]
83mod write;
84
85use std::convert::{TryFrom, TryInto};
86use std::error::Error;
87use std::fs::File;
88use std::io::{BufWriter, Cursor, Read, Seek, SeekFrom, Write};
89use std::path::Path;
90use std::sync::Arc;
91use std::{fmt, mem, str};
92
93use arcstr::ArcStr;
94use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
95use chrono::prelude::*;
96use chrono::{Datelike, NaiveDate, NaiveDateTime};
97use derive_more::{self, Add, AddAssign, Sub, SubAssign};
98use num_derive::FromPrimitive;
99use num_traits::FromPrimitive;
100use serde::{Deserialize, Serialize};
101#[macro_use]
102extern crate derive_builder;
103
104// Internal Modules
105use read::{GdsParser, GdsScanner, GdsStructScan};
106pub use ser::{SerdeFile, SerializationFormat};
107use write::GdsWriter;
108
109/// An enumeration of GDS record types.
110///
111/// In the numeric-order specified by GDSII, for automatic [`FromPrimitive`] conversions.
112#[derive(FromPrimitive, Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
113#[allow(missing_docs)]
114pub enum GdsRecordType {
115    Header = 0x00,
116    BgnLib,
117    LibName,
118    Units,
119    EndLib,
120    BgnStruct,
121    StructName, // STRNAME
122    EndStruct,
123    Boundary,
124    Path,
125    StructRef,
126    ArrayRef,
127    Text,
128    Layer,
129    DataType,
130    Width,
131    Xy,
132    EndElement,
133    StructRefName, // SNAME
134    ColRow,
135    TextNode, // "Not currently used"
136    Node,
137    TextType,
138    Presentation,
139    Spacing, // "Discontinued"
140    String,
141    Strans,
142    Mag,
143    Angle,
144    Uinteger, // "No longer used"
145    Ustring,  // "No longer used"
146    RefLibs,
147    Fonts,
148    PathType,
149    Generations,
150    AttrTable,
151    StypTable, // "Unreleased Feature"
152    StrType,   // "Unreleased Feature"
153    ElemFlags,
154    ElemKey,  // "Unreleased Feature"
155    LinkType, // "Unreleased Feature"
156    LinkKeys, // "Unreleased Feature"
157    Nodetype,
158    PropAttr,
159    PropValue,
160    Box,
161    BoxType,
162    Plex,
163    BeginExtn, // "Only occurs in CustomPlus"
164    EndExtn,   // "Only occurs in CustomPlus"
165    TapeNum,
166    TapeCode,
167    StrClass, // "Only for Calma internal use"
168    Reserved, // "Reserved for future use"
169    Format,
170    Mask,
171    EndMasks,
172    LibDirSize,
173    SrfName,
174    LibSecur,
175}
176
177impl GdsRecordType {
178    /// Returns whether a record type is valid.
179    ///
180    /// Many are either deprecated or provisioned without ever being implemented;
181    /// all from this list are deemed invalid.
182    pub fn valid(&self) -> bool {
183        match self {
184            Self::TextNode | // "Not currently used"
185            Self::Spacing | // "Discontinued"
186            Self::Uinteger | // "No longer used"
187            Self::Ustring |  // "No longer used"
188            Self::StypTable | // "Unreleased Feature"
189            Self::StrType |   // "Unreleased Feature"
190            Self::ElemKey |   // "Unreleased Feature"
191            Self::LinkType |  // "Unreleased Feature"
192            Self::LinkKeys |  // "Unreleased Feature"
193            Self::StrClass | // "Only for Calma internal use"
194            Self::Reserved   // "Reserved for future use"
195              => false,
196            _ => true,
197        }
198    }
199}
200
201/// An enumeration of GDS data types.
202///
203/// Listed in order as decoded from 16-bit integers in binary data.
204#[derive(FromPrimitive, Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
205#[allow(missing_docs)]
206pub enum GdsDataType {
207    NoData = 0,
208    BitArray = 1,
209    I16 = 2,
210    I32 = 3,
211    F32 = 4,
212    F64 = 5,
213    Str = 6,
214}
215
216/// A GDS record header.
217///
218/// Decoded contents of a record's four header bytes,
219/// including its record-type, data-type, and length in bytes.
220#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
221pub struct GdsRecordHeader {
222    rtype: GdsRecordType,
223    dtype: GdsDataType,
224    len: u16,
225}
226
227/// An enumeration of GDS record types.
228///
229/// Keeps each record in relatively "raw" form,
230/// other than assuring correct data-types,
231/// and converting one-entry arrays into scalars.
232/// Invalid record-types are not included.
233#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234#[allow(missing_docs)]
235pub enum GdsRecord {
236    Header { version: i16 },
237    BgnLib { dates: Vec<i16> }, // Note: always length 12
238    LibName(ArcStr),
239    Units(f64, f64),
240    EndLib,
241    BgnStruct { dates: Vec<i16> }, // Note: always length 12
242    StructName(ArcStr),            // STRNAME Record
243    StructRefName(ArcStr),         // SNAME Record
244    EndStruct,
245    Boundary,
246    Path,
247    StructRef,
248    ArrayRef,
249    Text,
250    Layer(i16),
251    DataType(i16),
252    Width(i32),
253    Xy(Vec<i32>),
254    EndElement,
255    ColRow { cols: i16, rows: i16 },
256    Node,
257    TextType(i16),
258    Presentation(u8, u8),
259    String(ArcStr),
260    Strans(u8, u8),
261    Mag(f64),
262    Angle(f64),
263    RefLibs(ArcStr),
264    Fonts(ArcStr),
265    PathType(i16),
266    Generations(i16),
267    AttrTable(ArcStr),
268    ElemFlags(u8, u8),
269    Nodetype(i16),
270    PropAttr(i16),
271    PropValue(ArcStr),
272    Box,
273    BoxType(i16),
274    Plex(i32),
275    BeginExtn(i32),
276    EndExtn(i32),
277    TapeNum(i16),
278    TapeCode(Vec<i16>), // Note: always length 6
279    Format(i16),
280    Mask(ArcStr),
281    EndMasks,
282    LibDirSize(i16),
283    SrfName(ArcStr),
284    LibSecur(i16),
285}
286
287/// A namespace for encoding and decoding GDSII floats to and from the IEEE754 double-precision
288/// format.
289pub struct GdsFloat64;
290
291impl GdsFloat64 {
292    /// Decodes GDSII's eight-byte representation, stored as a `u64`, to IEEE (and Rust)-compatible `f64`.
293    pub fn decode(val: u64) -> f64 {
294        // Extract the MSB Sign bit
295        let neg = (val & 0x8000_0000_0000_0000) != 0;
296        // Extract the 7b exponent
297        let exp: i32 = ((val & 0x7F00_0000_0000_0000) >> (8 * 7)) as i32 - 64;
298        // Create the initially integer-valued mantissa from the 7 least-significant bytes
299        let mantissa: u64 = val & 0x00FF_FFFF_FFFF_FFFF;
300        // And apply its normalization to the range (1/16, 1)
301        let mantissa: f64 = mantissa as f64 / 2f64.powi(8 * 7);
302        // Combine everything into our overall value
303        if neg {
304            -mantissa * 16f64.powi(exp)
305        } else {
306            mantissa * 16f64.powi(exp)
307        }
308    }
309    /// Encodes `f64` to GDSII's eight bytes, stored as `u64`.
310    pub fn encode(mut val: f64) -> u64 {
311        if val == 0.0 {
312            return 0;
313        };
314        let mut top: u8 = 0;
315        if val < 0.0 {
316            top = 0x80;
317            val = -val;
318        }
319        let fexp: f64 = 0.25 * val.log2();
320        let mut exponent = fexp.ceil() as i32;
321        if fexp == fexp.ceil() {
322            exponent += 1;
323        }
324        let mantissa: u64 = (val * 16_f64.powi(14 - exponent)).round() as u64;
325        top += (64 + exponent) as u8;
326        let result: u64 = (top as u64).wrapping_shl(56) | (mantissa & 0x00FF_FFFF_FFFF_FFFF);
327        result
328    }
329}
330
331/// A marker type for unsupported features.
332#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
333pub struct Unsupported;
334
335/// A GDS translation setting.
336///
337/// Reflection, rotation, and magnification for text-elements and references.
338/// As configured by `STRANS` records.
339#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)]
340pub struct GdsStrans {
341    // Required Fields
342    /// Reflection about the x-axis.
343    ///
344    /// Applied before rotation.
345    pub reflected: bool,
346    /// Absolute magnification setting
347    pub abs_mag: bool,
348    /// Absolute angle setting
349    pub abs_angle: bool,
350
351    // Optional Fields
352    /// Magnification factor. Defaults to 1.0 if not specified.
353    #[serde(default, skip_serializing_if = "Option::is_none")]
354    pub mag: Option<f64>,
355    /// Angle in degrees counter-clockwise. Defaults to zero if not specified.
356    #[serde(default, skip_serializing_if = "Option::is_none")]
357    pub angle: Option<f64>,
358}
359
360/// GDS text presentation flags.
361///
362/// Sets fonts, text justification, and the like.
363/// Stored in raw `u8` form.
364#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
365pub struct GdsPresentation(u8, u8);
366
367/// GDS element flags.
368///
369/// As configured by `ELFLAGS` records.
370/// Two bytes of bit-fields stored in raw `u8` form.
371#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
372pub struct GdsElemFlags(u8, u8);
373
374/// A GDS plex record.
375///
376/// From the spec:
377/// "A unique positive number which is common to all elements of the Plex to which this element belongs."
378/// In Gds21's experience, `PLEX` records and settings are highly uncommon.
379#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
380pub struct GdsPlex(i32);
381
382/// An encoding of GDS units.
383///
384/// Each GDSII Library has two length-units, referred to as "DB Units" and "User Units" respectively.
385/// Essentially all spatial data throughout the Library is denoted in "DB Units".
386/// "User units" are a sort of recommendation for GUI programs to use when displaying the Library.  
387///
388/// From the spec's `UNITS` record-description:  
389/// ```text
390/// Contains two eight-byte real numbers.
391/// The first number is the size of a database-unit, in user-units.
392/// The second is the size of a database-unit in meters.
393/// To calculate the size of a user-unit in meters, divide the second number by the first.
394/// ```
395///
396/// These two numbers are stored as-is in the [GdsUnits] tuple-struct.
397#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
398pub struct GdsUnits(f64, f64);
399
400impl GdsUnits {
401    /// Creates a new [GdsUnits]
402    pub const fn new(num1: f64, num2: f64) -> Self {
403        Self(num1, num2)
404    }
405    /// Gets the database-unit size in meters. Used for all spatial data.
406    pub const fn db_unit(&self) -> f64 {
407        self.1
408    }
409    /// Gets the user-unit size in meters. Largely for display/debug.
410    pub const fn user_unit(&self) -> f64 {
411        self.0 / self.1
412    }
413}
414
415impl Default for GdsUnits {
416    /// Default values for GDS units:
417    /// * DB-Unit = 1nm
418    /// * User-Unit = 1µm (1000x the DB-Unit)
419    fn default() -> Self {
420        Self(1e-3, 1e-9)
421    }
422}
423
424/// A GDS spatial point.
425///
426/// Coordinate in (x,y) layout-space.
427/// Denoted in each [GdsLibrary]'s [GdsUnits].
428#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
429#[allow(missing_docs)]
430pub struct GdsPoint {
431    pub x: i32,
432    pub y: i32,
433}
434
435impl GdsPoint {
436    /// Creates a new [GdsPoint].
437    pub fn new(x: i32, y: i32) -> Self {
438        GdsPoint { x, y }
439    }
440
441    /// Creates a vector of [GdsPoint] from an array of tuples.
442    pub fn vec(pts: &[(i32, i32)]) -> Vec<Self> {
443        pts.iter().map(|pt| Self::new(pt.0, pt.1)).collect()
444    }
445
446    /// Converts from a two-element slice.
447    fn parse(from: &[i32]) -> GdsResult<Self> {
448        if from.len() != 2 {
449            return Err(GdsError::Str(
450                "GdsPoint coordinate vector: Invalid number of elements".into(),
451            ));
452        }
453        Ok(GdsPoint {
454            x: from[0],
455            y: from[1],
456        })
457    }
458
459    /// Converts an n-element vector if `i32` into an n/2-element vector of [GdsPoint]s.
460    fn parse_vec(from: &[i32]) -> GdsResult<Vec<GdsPoint>> {
461        if !from.len().is_multiple_of(2) {
462            return Err(GdsError::Str(
463                "GdsPoint coordinate vector: Invalid number of elements".into(),
464            ));
465        }
466        let mut rv = Vec::with_capacity(from.len() / 2);
467        for i in 0..from.len() / 2 {
468            rv.push(GdsPoint {
469                x: from[i * 2],
470                y: from[i * 2 + 1],
471            });
472        }
473        Ok(rv)
474    }
475
476    /// Flattens to a two-element vector
477    fn flatten(&self) -> Vec<i32> {
478        vec![self.x, self.y]
479    }
480
481    /// Converts an n-element slice of [GdsPoint]s to a 2n-element i32 vector.
482    fn flatten_vec(src: &[GdsPoint]) -> Vec<i32> {
483        let mut rv = Vec::with_capacity(src.len() * 2);
484        for pt in src.iter() {
485            rv.push(pt.x);
486            rv.push(pt.y);
487        }
488        rv
489    }
490}
491
492impl std::fmt::Display for GdsPoint {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        write!(f, "({}, {})", self.x, self.y)
495    }
496}
497
498/// An enumeration of GDS mask formats.
499///
500/// As set by the FORMAT record.
501#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
502pub enum GdsFormatType {
503    /// Default, sole fully-supported case.
504    Archive,
505    /// Filtered-format includes a list of Mask records. Not supported.
506    Filtered(Vec<Unsupported>),
507}
508
509/// A GDS property specification.
510///
511/// Spec BNF:
512/// ```text
513/// PROPATTR PROPVALUE
514/// ```
515#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)]
516pub struct GdsProperty {
517    /// Attribute Number
518    pub attr: i16,
519    /// Attribute Value
520    pub value: ArcStr,
521}
522
523/// A GDS path element.
524///
525/// Spec BNF:
526/// ```text
527/// PATH [ELFLAGS] [PLEX] LAYER DATATYPE [PATHTYPE] [WIDTH] XY [BGNEXTN] [ENDEXTN])
528/// ```
529#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
530#[builder(pattern = "owned", setter(into), private)]
531#[allow(missing_docs)]
532pub struct GdsPath {
533    // Required Fields
534    /// Layer number.
535    pub layer: i16,
536    /// Data type ID.
537    pub datatype: i16,
538    /// Vector of x,y coordinates.
539    pub xy: Vec<GdsPoint>,
540
541    // Optional Fields
542    #[serde(default, skip_serializing_if = "Option::is_none")]
543    #[builder(default, setter(strip_option))]
544    pub width: Option<i32>,
545    #[serde(default, skip_serializing_if = "Option::is_none")]
546    #[builder(default, setter(strip_option))]
547    pub path_type: Option<i16>,
548    #[serde(default, skip_serializing_if = "Option::is_none")]
549    #[builder(default, setter(strip_option))]
550    pub begin_extn: Option<i32>,
551    #[serde(default, skip_serializing_if = "Option::is_none")]
552    #[builder(default, setter(strip_option))]
553    pub end_extn: Option<i32>,
554    #[serde(default, skip_serializing_if = "Option::is_none")]
555    #[builder(default, setter(strip_option))]
556    pub elflags: Option<GdsElemFlags>,
557    #[serde(default, skip_serializing_if = "Option::is_none")]
558    #[builder(default, setter(strip_option))]
559    pub plex: Option<GdsPlex>,
560    #[serde(default, skip_serializing_if = "Vec::is_empty")]
561    #[builder(default, setter(strip_option))]
562    pub properties: Vec<GdsProperty>,
563}
564
565/// A GDS boundary element.
566///
567/// The most common type for closed-form shapes in GDSII.
568/// Most IC layout is comprised of [GdsBoundary] elements, which represent individual polygons.
569/// GDSII dictates that the first two and final two coordinates in each [GdsBoundary]
570/// shall be identical, "closing" the polygon.
571/// Hence an N-sided polygon is represented by an (N+1)-point `xy` vector.
572///
573/// Spec BNF:
574/// ```text
575/// BOUNDARY [ELFLAGS] [PLEX] LAYER DATATYPE XY
576/// ```
577#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
578#[builder(pattern = "owned", setter(into), private)]
579#[allow(missing_docs)]
580pub struct GdsBoundary {
581    // Required Fields
582    /// Layer number.
583    pub layer: i16,
584    /// Data type ID.
585    pub datatype: i16,
586    /// Vector of x,y coordinates.
587    pub xy: Vec<GdsPoint>,
588
589    // Optional Fields
590    #[serde(default, skip_serializing_if = "Option::is_none")]
591    #[builder(default, setter(strip_option))]
592    pub elflags: Option<GdsElemFlags>,
593    #[serde(default, skip_serializing_if = "Option::is_none")]
594    #[builder(default, setter(strip_option))]
595    pub plex: Option<GdsPlex>,
596    #[serde(default, skip_serializing_if = "Vec::is_empty")]
597    #[builder(default, setter(strip_option))]
598    pub properties: Vec<GdsProperty>,
599}
600
601/// A GDS struct reference (cell instance).
602///
603/// Represents an instance of a layout cell.
604/// Coordinate vector `xy` is dictated by spec to have exactly one point (or two numbers),
605/// specifying the instance's lower-left coordinate.
606/// Options for rotation and reflection are configured in the [GdsStrans] attribute `strans`.
607///
608/// Spec BNF:
609/// ```text
610/// SREF [ELFLAGS] [PLEX] SNAME [<strans>] XY
611/// ```
612#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
613#[builder(pattern = "owned", setter(into), private)]
614#[allow(missing_docs)]
615pub struct GdsStructRef {
616    // Required Fields
617    /// Struct (cell) name.
618    pub name: ArcStr,
619    /// Location x,y coordinates.
620    pub xy: GdsPoint,
621
622    // Optional Fields
623    #[serde(default, skip_serializing_if = "Option::is_none")]
624    #[builder(default, setter(strip_option))]
625    /// Translation & reflection options.
626    pub strans: Option<GdsStrans>,
627    #[serde(default, skip_serializing_if = "Option::is_none")]
628    #[builder(default, setter(strip_option))]
629    pub elflags: Option<GdsElemFlags>,
630    #[serde(default, skip_serializing_if = "Option::is_none")]
631    #[builder(default, setter(strip_option))]
632    pub plex: Option<GdsPlex>,
633    #[serde(default, skip_serializing_if = "Vec::is_empty")]
634    #[builder(default, setter(strip_option))]
635    pub properties: Vec<GdsProperty>,
636}
637
638/// A GDS array reference.
639///
640/// A two-dimensional array of struct (cell) instances.
641///
642/// Spec BNF:
643/// ```text
644/// AREF [ELFLAGS] [PLEX] SNAME [<strans>] COLROW XY
645/// ```
646#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
647#[builder(pattern = "owned", setter(into), private)]
648#[allow(missing_docs)]
649pub struct GdsArrayRef {
650    // Required Fields
651    /// Struct (cell) name.
652    pub name: ArcStr,
653    /// Vector of x,y coordinates.
654    pub xy: [GdsPoint; 3],
655    /// Number of columns.
656    pub cols: i16,
657    /// Number of rows.
658    pub rows: i16,
659    // Optional Fields
660    /// Translation & reflection options.
661    #[serde(default, skip_serializing_if = "Option::is_none")]
662    #[builder(default)]
663    pub strans: Option<GdsStrans>,
664    #[serde(default, skip_serializing_if = "Option::is_none")]
665    #[builder(default, setter(strip_option))]
666    pub elflags: Option<GdsElemFlags>,
667    #[serde(default, skip_serializing_if = "Option::is_none")]
668    #[builder(default, setter(strip_option))]
669    pub plex: Option<GdsPlex>,
670    #[serde(default, skip_serializing_if = "Vec::is_empty")]
671    #[builder(default, setter(strip_option))]
672    pub properties: Vec<GdsProperty>,
673}
674
675/// A GDS text element.
676///
677/// Spec BNF:
678/// ```text
679/// TEXT [ELFLAGS] [PLEX] LAYER
680/// TEXTTYPE [PRESENTATION] [PATHTYPE] [WIDTH] [<strans>] XY STRING
681/// ```
682#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
683#[builder(pattern = "owned", setter(into), private)]
684#[allow(missing_docs)]
685pub struct GdsTextElem {
686    // Required Fields
687    /// Text value.
688    pub string: ArcStr,
689    /// Layer number.
690    pub layer: i16,
691    /// Text-type ID.
692    pub texttype: i16,
693    /// Vector of x,y coordinates.
694    pub xy: GdsPoint,
695
696    // Optional Fields
697    #[serde(default, skip_serializing_if = "Option::is_none")]
698    #[builder(default, setter(strip_option))]
699    pub presentation: Option<GdsPresentation>,
700    #[serde(default, skip_serializing_if = "Option::is_none")]
701    #[builder(default, setter(strip_option))]
702    pub path_type: Option<i16>,
703    #[serde(default, skip_serializing_if = "Option::is_none")]
704    #[builder(default, setter(strip_option))]
705    pub width: Option<i32>,
706    #[serde(default, skip_serializing_if = "Option::is_none")]
707    #[builder(default)]
708    /// Translation & reflection options.
709    pub strans: Option<GdsStrans>,
710    #[serde(default, skip_serializing_if = "Option::is_none")]
711    #[builder(default, setter(strip_option))]
712    pub elflags: Option<GdsElemFlags>,
713    #[serde(default, skip_serializing_if = "Option::is_none")]
714    #[builder(default, setter(strip_option))]
715    pub plex: Option<GdsPlex>,
716    #[serde(default, skip_serializing_if = "Vec::is_empty")]
717    #[builder(default, setter(strip_option))]
718    pub properties: Vec<GdsProperty>,
719}
720
721/// GDS node element
722///
723/// Spec BNF:
724/// ```text
725/// NODE [ELFLAGS] [PLEX] LAYER NODETYPE XY
726/// ```
727#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
728#[builder(pattern = "owned", setter(into), private)]
729#[allow(missing_docs)]
730pub struct GdsNode {
731    // Required Fields
732    /// Layer number.
733    pub layer: i16,
734    /// Node type ID.
735    pub nodetype: i16,
736    /// Vector of x,y coordinates.
737    pub xy: Vec<GdsPoint>,
738
739    // Optional Fields
740    #[serde(default, skip_serializing_if = "Option::is_none")]
741    #[builder(default, setter(strip_option))]
742    pub elflags: Option<GdsElemFlags>,
743    #[serde(default, skip_serializing_if = "Option::is_none")]
744    #[builder(default, setter(strip_option))]
745    pub plex: Option<GdsPlex>,
746    #[serde(default, skip_serializing_if = "Vec::is_empty")]
747    #[builder(default, setter(strip_option))]
748    pub properties: Vec<GdsProperty>,
749}
750
751/// A GDS box element.
752///
753/// Spec BNF:
754/// ```text
755/// BOX [ELFLAGS] [PLEX] LAYER BOXTYPE XY
756/// ```
757#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
758#[builder(pattern = "owned", setter(into), private)]
759#[allow(missing_docs)]
760pub struct GdsBox {
761    // Required Fields
762    /// Layer number.
763    pub layer: i16,
764    /// Box type ID.
765    pub boxtype: i16,
766    /// Vector of x,y coordinates.
767    pub xy: [GdsPoint; 5],
768
769    // Optional Fields
770    #[serde(default, skip_serializing_if = "Option::is_none")]
771    #[builder(default, setter(strip_option))]
772    pub elflags: Option<GdsElemFlags>,
773    #[serde(default, skip_serializing_if = "Option::is_none")]
774    #[builder(default, setter(strip_option))]
775    pub plex: Option<GdsPlex>,
776    #[serde(default, skip_serializing_if = "Vec::is_empty")]
777    #[builder(default, setter(strip_option))]
778    pub properties: Vec<GdsProperty>,
779}
780
781/// An enumeration of GDS elements.
782///
783/// Primary union of geometric elements, instances, and arrays which comprise a GDSII struct (cell).
784///
785/// Spec BNF:
786/// ```text
787/// {<boundary> | <path> | <SREF> | <AREF> | <text> | <node> | <box>} {<property>}* ENDEL
788/// ```
789///
790/// Note the `properties` vectors are pushed down to each enum variant.
791#[derive(derive_more::From, Debug, Clone, Deserialize, Serialize, PartialEq)]
792#[allow(missing_docs)]
793pub enum GdsElement {
794    GdsBoundary(GdsBoundary),
795    GdsPath(GdsPath),
796    GdsStructRef(GdsStructRef),
797    GdsArrayRef(GdsArrayRef),
798    GdsTextElem(GdsTextElem),
799    GdsNode(GdsNode),
800    GdsBox(GdsBox),
801}
802
803/// GDS summary stats.
804///
805/// Summary statistics for a [GdsLibrary] or [GdsStruct].  
806/// Total numbers of elements of each type.
807#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Add, AddAssign, Sub, SubAssign)]
808pub struct GdsStats {
809    libraries: usize,
810    structs: usize,
811    boundaries: usize,
812    paths: usize,
813    struct_refs: usize,
814    array_refs: usize,
815    text_elems: usize,
816    nodes: usize,
817    boxes: usize,
818}
819
820/// GDS modification dates and times.
821#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
822pub struct GdsDateTimes {
823    /// Last modification date and time.
824    pub modified: NaiveDateTime,
825    /// Last access date and time.
826    pub accessed: NaiveDateTime,
827}
828
829impl Default for GdsDateTimes {
830    /// Default dates and times.
831    fn default() -> Self {
832        let now = Utc::now().naive_utc();
833        Self {
834            modified: now,
835            accessed: now,
836        }
837    }
838}
839
840/// A GDS struct (cell) definition
841///
842/// GDSII's primary hierarchical layout-definition object is its "struct",
843/// which most other layout systems would call a "cell" or "module".
844/// (Most GDSII software calls them one of these as well.)  
845///
846/// [GdsStruct]s are principally composed of an un-ordered, un-indexed vector
847/// of [GdsElement]s, which can be polygons ([GdsBoundary]),
848/// instances of other layouts ([GdsStructRef]),
849/// two-dimensional arrays thereof ([GdsArrayRef]),
850/// and a handful of other [GdsElement]s.  
851///
852/// Spec BNF:
853/// ```text
854/// BGNSTR STRNAME [STRCLASS] {<element>}* ENDSTR
855/// ```
856#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
857#[builder(pattern = "owned", setter(into), private)]
858pub struct GdsStruct {
859    /// Struct name.
860    pub name: ArcStr,
861    /// Creation/modification date info.
862    pub dates: GdsDateTimes,
863    /// Elements list.
864    pub elems: Vec<GdsElement>,
865}
866impl GdsStruct {
867    /// Creates a new and empty [GdsStruct].
868    pub fn new(name: impl Into<ArcStr>) -> Self {
869        Self {
870            name: name.into(),
871            ..Default::default()
872        }
873    }
874    /// Counts and returns element statistics.
875    fn stats(&self) -> GdsStats {
876        let mut stats = GdsStats::default();
877        stats.structs += 1;
878        for elem in &self.elems {
879            use GdsElement::*;
880            match elem {
881                GdsBoundary(_) => stats.boundaries += 1,
882                GdsPath(_) => stats.paths += 1,
883                GdsStructRef(_) => stats.struct_refs += 1,
884                GdsArrayRef(_) => stats.array_refs += 1,
885                GdsTextElem(_) => stats.text_elems += 1,
886                GdsNode(_) => stats.nodes += 1,
887                GdsBox(_) => stats.boxes += 1,
888            };
889        }
890        stats
891    }
892}
893
894/// A GDS library.
895///
896/// The Library is GDSII's primary idiom for a suite of layout-cells.
897/// A Library generally corresponds one-to-one with a `.gds` file.
898/// Libraries consist primarily of cell-definitions ([GdsStruct]s),
899/// and secondarily include library-level meta-data, including the distance units, GDS-spec version, and modification dates.
900///
901/// Several more esoteric library-level GDSII features are included as [GdsLibrary] fields,
902/// but are not materially supported. The empty [Unsupported] value generally denotes these fields.
903///
904/// Spec BNF:
905/// ```text
906/// HEADER BGNLIB [LIBDIRSIZE] [SRFNAME] [LIBSECUR] LIBNAME [REFLIBS] [FONTS] [ATTRTABLE] [GENERATIONS] [<FormatType>]
907/// UNITS {<structure>}* ENDLIB
908/// ```
909#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
910#[builder(pattern = "owned", setter(into), private)]
911#[allow(missing_docs)]
912pub struct GdsLibrary {
913    // Required fields
914    /// Library name.
915    pub name: ArcStr,
916    /// Gds spec version.
917    pub version: i16,
918    /// Modification date(s).
919    pub dates: GdsDateTimes,
920    /// Spatial units.
921    pub units: GdsUnits,
922    /// Struct definitions.
923    pub structs: Vec<GdsStruct>,
924
925    // Unsupported Fields
926    #[serde(default, skip_serializing)]
927    #[builder(default)]
928    pub libdirsize: Unsupported,
929    #[serde(default, skip_serializing)]
930    #[builder(default)]
931    pub srfname: Unsupported,
932    #[serde(default, skip_serializing)]
933    #[builder(default)]
934    pub libsecur: Unsupported,
935    #[serde(default, skip_serializing)]
936    #[builder(default)]
937    pub reflibs: Unsupported,
938    #[serde(default, skip_serializing)]
939    #[builder(default)]
940    pub fonts: Unsupported,
941    #[serde(default, skip_serializing)]
942    #[builder(default)]
943    pub attrtable: Unsupported,
944    #[serde(default, skip_serializing)]
945    #[builder(default)]
946    pub generations: Unsupported,
947    #[serde(default, skip_serializing)]
948    #[builder(default)]
949    pub format_type: Unsupported,
950}
951
952impl GdsLibrary {
953    /// Creates a new and empty [GdsLibrary].
954    pub fn new(name: impl Into<ArcStr>) -> Self {
955        Self {
956            name: name.into(),
957            version: 3,
958            ..Default::default()
959        }
960    }
961
962    /// Creates a new and empty [GdsLibrary] with the given units.
963    pub fn with_units(name: impl Into<ArcStr>, units: GdsUnits) -> Self {
964        Self {
965            name: name.into(),
966            version: 3,
967            units,
968            ..Default::default()
969        }
970    }
971
972    /// Reads a GDS loaded from file at path `fname`.
973    pub fn load(fname: impl AsRef<Path>) -> GdsResult<GdsLibrary> {
974        // Create the parser, and parse a library.
975        GdsParser::open(fname)?.parse_lib()
976    }
977
978    /// Reads a [GdsLibrary] from byte-vector `bytes`.
979    pub fn from_bytes(bytes: Vec<u8>) -> GdsResult<GdsLibrary> {
980        // Create the parser, and parse a Library
981        GdsParser::from_bytes(bytes)?.parse_lib()
982    }
983
984    /// Runs a first-pass scan of GDSII data in `fname`.
985    ///
986    /// Returns a vector of [GdsStructScan]s including summary info per struct.
987    #[allow(dead_code)] // FIXME!
988    fn scan(fname: impl AsRef<Path>) -> GdsResult<Vec<GdsStructScan>> {
989        GdsScanner::scan(fname)
990    }
991
992    /// Collects and returns the library's aggregate statistics
993    /// (numbers of structs, elements by type).
994    pub fn stats(&self) -> GdsStats {
995        let mut stats = GdsStats::default();
996        stats.libraries += 1;
997        for strukt in self.structs.iter() {
998            stats += strukt.stats();
999        }
1000        stats
1001    }
1002
1003    /// Saves to file at path `fname`.
1004    pub fn save(&self, fname: impl AsRef<Path>) -> GdsResult<()> {
1005        if let Some(prefix) = fname.as_ref().parent() {
1006            std::fs::create_dir_all(prefix)?;
1007        }
1008        let mut wr = GdsWriter::open(fname)?;
1009        wr.write_lib(self)
1010    }
1011
1012    /// Writes to file `file`.
1013    pub fn write(&self, file: impl Write) -> GdsResult<()> {
1014        let mut wr = GdsWriter::new(file);
1015        wr.write_lib(self)
1016    }
1017}
1018
1019// Enable [GdsLibrary] and [GdsStruct] serialization to file, in each of `utils` supported formats.
1020impl SerdeFile for GdsLibrary {}
1021impl SerdeFile for GdsStruct {}
1022
1023/// A GDS layer spec.
1024///
1025/// Each GDSII element's layer is specified by a set of two numbers,
1026/// commonly referred to as `layer` and `datatype`.
1027/// Several element-types refer to their analog of `datatype` by different names,
1028/// e.g. `texttype` and `nodetype`.  
1029///
1030/// `GdsLayerSpecs` generalize across these via the `xtype` field,
1031/// which holds whichever is appropriate for the given element.
1032#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1033pub struct GdsLayerSpec {
1034    /// Layer ID number.
1035    pub layer: i16,
1036    /// Data type (or text type, node type, etc.) ID number.
1037    pub xtype: i16,
1038}
1039
1040/// An object that has a corresponding GDS layer.
1041pub trait HasLayer {
1042    /// Returns a [GdsLayerSpec] including the two numbers `layer` and `xtype`.
1043    fn layerspec(&self) -> GdsLayerSpec;
1044}
1045
1046impl GdsLayerSpec {
1047    /// Creates a new [GdsLayerSpec].
1048    pub fn new(layer: i16, xtype: i16) -> GdsLayerSpec {
1049        GdsLayerSpec { layer, xtype }
1050    }
1051}
1052
1053impl HasLayer for GdsBoundary {
1054    fn layerspec(&self) -> GdsLayerSpec {
1055        GdsLayerSpec::new(self.layer, self.datatype)
1056    }
1057}
1058
1059impl HasLayer for GdsTextElem {
1060    fn layerspec(&self) -> GdsLayerSpec {
1061        GdsLayerSpec::new(self.layer, self.texttype)
1062    }
1063}
1064
1065impl HasLayer for GdsNode {
1066    fn layerspec(&self) -> GdsLayerSpec {
1067        GdsLayerSpec::new(self.layer, self.nodetype)
1068    }
1069}
1070
1071impl HasLayer for GdsBox {
1072    fn layerspec(&self) -> GdsLayerSpec {
1073        GdsLayerSpec::new(self.layer, self.boxtype)
1074    }
1075}
1076
1077impl HasLayer for GdsPath {
1078    fn layerspec(&self) -> GdsLayerSpec {
1079        GdsLayerSpec::new(self.layer, self.datatype)
1080    }
1081}
1082
1083/// An enumeration of each context in which a record can be parsed, primarily for error reporting.
1084#[derive(Debug, Clone)]
1085#[allow(missing_docs)]
1086pub enum GdsContext {
1087    Library,
1088    Struct,
1089    StructRef,
1090    ArrayRef,
1091    Boundary,
1092    Box,
1093    Path,
1094    Text,
1095    Node,
1096    Property,
1097}
1098
1099/// A result type alias.
1100pub type GdsResult<T> = Result<T, GdsError>;
1101
1102/// An enumeration of GDS errors.
1103///
1104/// Most errors are tied in some sense to parsing and decoding.
1105/// Once a valid [GdsLibrary] is created in memory, it can generally be streamed to bytes.
1106#[derive(Debug, Clone)]
1107pub enum GdsError {
1108    /// Invalid binary -> record conversion.
1109    RecordDecode(GdsRecordType, GdsDataType, u16),
1110    /// Invalid record length.
1111    RecordLen(usize),
1112    /// Invalid data type.
1113    InvalidDataType(u8),
1114    /// Invalid record type.
1115    InvalidRecordType(u8),
1116    /// Unsupported feature, in the decoded context.
1117    Unsupported(Option<GdsRecord>, Option<GdsContext>),
1118    /// Parser errors.
1119    #[allow(missing_docs)]
1120    Parse {
1121        msg: String,
1122        record: GdsRecord,
1123        recordnum: usize,
1124        bytepos: u64,
1125        ctx: Vec<GdsContext>,
1126    },
1127    /// Boxed (external) errors.
1128    Boxed(Arc<dyn Error + Send + Sync>),
1129    /// Other errors.
1130    Str(String),
1131}
1132
1133impl std::fmt::Display for GdsError {
1134    /// Displays a [GdsError].
1135    ///
1136    /// This functionally delegates to the (derived) [std::fmt::Debug] implementation.
1137    /// Maybe more info that wanted in some cases. But certainly enough.
1138    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1139        write!(f, "{self:?}")
1140    }
1141}
1142
1143impl std::error::Error for GdsError {}
1144
1145impl From<std::io::Error> for GdsError {
1146    fn from(e: std::io::Error) -> Self {
1147        Self::Boxed(Arc::new(e))
1148    }
1149}
1150
1151impl From<std::str::Utf8Error> for GdsError {
1152    fn from(e: std::str::Utf8Error) -> Self {
1153        Self::Boxed(Arc::new(e))
1154    }
1155}
1156
1157impl From<String> for GdsError {
1158    fn from(e: String) -> Self {
1159        GdsError::Str(e)
1160    }
1161}
1162
1163impl From<&str> for GdsError {
1164    fn from(e: &str) -> Self {
1165        GdsError::Str(e.to_string())
1166    }
1167}
1168
1169#[cfg(any(test, feature = "selftest"))]
1170/// Check `lib` matches across a write-read round-trip cycle
1171pub fn roundtrip(lib: &GdsLibrary) -> GdsResult<()> {
1172    use tempfile::tempfile;
1173
1174    // Write to a temporary file
1175    let mut file = tempfile()?;
1176    lib.write(&mut file)?;
1177
1178    // Rewind to the file-start, and read it back
1179    file.rewind()?;
1180    let mut bytes = Vec::new();
1181    file.read_to_end(&mut bytes)?;
1182    let lib2 = GdsLibrary::from_bytes(bytes)?;
1183
1184    // And check the two line up
1185    assert_eq!(*lib, lib2);
1186    Ok(())
1187}