libreda_oasis/
lib.rs

1// Copyright (c) 2018-2021 Thomas Kramer.
2// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Library for reading and writing OASIS files.
7//!
8//! OASIS is a binary format for storing two-dimensional geometrical data as it is commonly used
9//! for silicon chip layouts. Its purpose is very similar to the older GDS2 format.
10//!
11//! # Examples
12//!
13//! ## Read a layout from OASIS
14//!
15//! ```
16//! use std::fs::File;
17//! use libreda_oasis::OASISStreamReader;
18//! // Import the `LayoutStreamReader` trait.
19//! use libreda_db::prelude::*;
20//!
21//! let filename = "./tests/data/INVX1_no_compression.oas";
22//! // Open the OASIS file for reading.
23//! let mut f = File::open(filename).unwrap();
24//!
25//! // Create an empty layout that will be populated by the OASIS reader.
26//! let mut layout = Chip::new();
27//!
28//! // Create a default OASIS reader and parse the data from the file.
29//! let result = OASISStreamReader::default()
30//!     .read_layout(&mut f, &mut layout);
31//!
32//! // Assert that there was no error.
33//! assert!(result.is_ok());
34//! ```
35//!
36//! ## Write a layout to OASIS
37//!
38//! ```
39//! use std::fs::File;
40//! use libreda_oasis::OASISStreamWriter;
41//! // Import the `LayoutStreamReader` trait.
42//! use libreda_db::prelude::*;
43//!
44//! // Create an empty layout.
45//! let layout = Chip::new();
46//!
47//! let mut f = File::create("./tests/data/empty_layout_out.oas").unwrap();
48//!
49//! let writer = OASISStreamWriter::default();
50//!
51//! // Write the (empty) layout to the file.
52//! let write_result = writer.write_layout(&mut f, &layout);
53//!
54//! // Assert that there was no error.
55//! assert!(write_result.is_ok());
56//! ```
57//!
58//! # References
59//!
60//! * [OASIS specification draft](https://web.archive.org/web/20200727024915if_/http://www.wrcad.com/oasis/oasis-3626-042303-draft.pdf)
61
62#![deny(missing_docs)]
63// As long as there are some unimplemented parts be less strict with warnings.
64// TODO: Remove this.
65#![allow(dead_code, unused_assignments)]
66
67#[macro_use]
68extern crate log;
69
70pub use libreda_db;
71
72mod base_types;
73mod reader;
74mod writer;
75
76use crate::base_types::Repetition;
77use base_types::*;
78use std::io::{Read, Write};
79
80pub use libreda_db::prelude::{LayoutBase, LayoutEdit, LayoutStreamReader, LayoutStreamWriter};
81pub use writer::OASISWriterConfig;
82
83/// Reader for the OASIS file format.
84#[derive(Clone, Default, Debug)]
85pub struct OASISStreamReader {}
86
87impl OASISStreamReader {
88    /// Create a new OASIS reader.
89    pub fn new() -> Self {
90        OASISStreamReader {}
91    }
92}
93
94/// Writer for the OASIS file format.
95#[derive(Clone, Default, Debug)]
96pub struct OASISStreamWriter {
97    config: OASISWriterConfig,
98}
99
100impl OASISStreamWriter {
101    /// Create a new OASIS writer with a custom configuration.
102    pub fn with_config(config: OASISWriterConfig) -> Self {
103        Self { config }
104    }
105}
106
107/// Reader implementation.
108impl LayoutStreamReader for OASISStreamReader {
109    type Error = OASISReadError;
110    fn read_layout<R: Read, L: LayoutEdit<Coord = SInt>>(
111        &self,
112        r: &mut R,
113        layout: &mut L,
114    ) -> Result<(), Self::Error> {
115        reader::read_layout(r, layout)
116    }
117}
118
119/// Writer implementation.
120impl LayoutStreamWriter for OASISStreamWriter {
121    type Error = OASISWriteError;
122    fn write_layout<W: Write, L: LayoutBase<Coord = SInt>>(
123        &self,
124        w: &mut W,
125        layout: &L,
126    ) -> Result<(), Self::Error> {
127        writer::write_layout(w, layout, &self.config)
128    }
129}
130
131/// Type for the `xy-mode` modal variable.
132#[derive(Copy, Clone, Debug, Default)]
133enum XYMode {
134    #[default]
135    Absolute,
136    Relative,
137}
138
139/// Datatype for either a name string or a reference number to a name string.
140/// In OASIS names can be given explicitly with a string or by reference number.
141/// In case of a reference number, the name string might be specified later in the file.
142#[derive(Debug, Clone)]
143pub(crate) enum NameOrRef {
144    /// A known name string.
145    Name(String),
146    /// A reference number to a name string.
147    NameRef(UInt),
148}
149
150/// Modal variables.
151/// Modal variables are used for implicit and context dependent values.
152/// At the beginning at the file or of a CELL record all modal variables are set to `None` except
153/// `placement_x`, `placement_y`, `geometry_x`, `geometry_y`, `text_x`, and `text_y`.
154#[derive(Debug)]
155struct Modal<C> {
156    /// Related records: PLACEMENT, TEXT, POLYGON, PATH,
157    /// RECTANGLE, TRAPEZOID, CTRAPEZOID,
158    /// CIRCLE, XGEOMETRY
159    repetition: Option<Repetition>,
160
161    /// Related records: PLACEMENT
162    placement_x: SInt,
163    /// Related records: PLACEMENT
164    placement_y: SInt,
165    /// Reference to an implicit cell to be used in the PLACEMENT record.
166    /// Related records: PLACEMENT
167    placement_cell: Option<C>,
168
169    /// Related records: POLYGON, PATH, RECTANGLE, TRAPEZOID,
170    /// CTRAPEZOID, CIRCLE, XGEOMETRY
171    layer: Option<UInt>,
172    /// Related records: POLYGON, PATH, RECTANGLE, TRAPEZOID,
173    /// CTRAPEZOID, CIRCLE, XGEOMETRY
174    datatype: Option<UInt>,
175
176    /// Related records: TEXT
177    textlayer: Option<UInt>,
178    /// Related records: TEXT
179    texttype: Option<UInt>,
180    /// Related records: TEXT
181    text_x: SInt,
182    /// Related records: TEXT
183    text_y: SInt,
184    /// Related records: TEXT
185    text_string: Option<String>,
186
187    /// Related records: POLYGON, PATH, RECTANGLE, TRAPEZOID
188    /// CTRAPEZOID, CIRCLE, XGEOMETRY
189    geometry_x: SInt,
190    /// Related records: POLYGON, PATH, RECTANGLE, TRAPEZOID
191    /// CTRAPEZOID, CIRCLE, XGEOMETRY
192    geometry_y: SInt,
193
194    /// Related records: PLACEMENT, TEXT, POLYGON, PATH,
195    /// RECTANGLE, TRAPEZOID, CTRAPEZOID,
196    /// CIRCLE, XGEOMETRY,
197    /// XYABSOLUTE, XYRELATIVE
198    /// Controls how `x` and `y` values are treated in the related records.
199    xy_mode: XYMode,
200
201    /// Related records: RECTANGLE, TRAPEZOID, CTRAPEZOID
202    geometry_w: Option<UInt>,
203    /// Related records: RECTANGLE, TRAPEZOID, CTRAPEZOID
204    geometry_h: Option<UInt>,
205
206    /// Related records: POLYGON
207    polygon_point_list: Option<PointList>,
208
209    /// Related records: PATH
210    path_halfwidth: Option<UInt>,
211    /// Related records: PATH
212    path_point_list: Option<PointList>,
213    /// Related records: PATH
214    path_start_extension: Option<SInt>,
215    /// Related records: PATH
216    path_end_extension: Option<SInt>,
217
218    /// Related records: CTRAPEZOID
219    ctrapezoid_type: Option<()>,
220
221    /// Related records: CIRCLE
222    circle_radius: Option<()>,
223
224    /// Related records: PROPERTY
225    last_property_name: Option<NameOrRef>,
226    /// Related records: PROPERTY
227    last_value_list: Option<Vec<PropertyValue>>,
228}
229
230impl<C> Default for Modal<C> {
231    fn default() -> Self {
232        Self {
233            repetition: None,
234            placement_x: Default::default(),
235            placement_y: Default::default(),
236            placement_cell: None,
237            layer: None,
238            datatype: None,
239            textlayer: None,
240            texttype: None,
241            text_x: Default::default(),
242            text_y: Default::default(),
243            text_string: None,
244            geometry_x: Default::default(),
245            geometry_y: Default::default(),
246            xy_mode: Default::default(),
247            geometry_w: None,
248            geometry_h: None,
249            polygon_point_list: None,
250            path_halfwidth: None,
251            path_point_list: None,
252            path_start_extension: None,
253            path_end_extension: None,
254            ctrapezoid_type: None,
255            circle_radius: None,
256            last_property_name: None,
257            last_value_list: None,
258        }
259    }
260}
261
262impl<C> Modal<C> {
263    /// Set all modal variables to `None` except
264    /// `placement_x`, `placement_y`, `geometry_x`, `geometry_y`, `text_x`, and `text_y` which are set to `0`.
265    fn reset(&mut self) {
266        let reset = Self::default();
267        *self = reset;
268    }
269}