1use super::*;
5
6pub struct GdsWriter<'wr> {
8 dest: Box<dyn Write + 'wr>,
10}
11
12impl<'wr> GdsWriter<'wr> {
13 pub fn open(fname: impl AsRef<Path>) -> GdsResult<Self> {
15 Ok(Self::new(File::create(fname)?))
16 }
17
18 pub fn new(dest: impl Write + 'wr) -> Self {
22 Self {
23 dest: Box::new(BufWriter::new(dest)),
24 }
25 }
26
27 pub fn write_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
29 self.encode_lib(lib)?;
32 self.dest.flush()?;
34 Ok(())
35 }
36
37 fn write_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> {
39 for r in records {
40 self.write_record(r)?;
41 }
42 Ok(())
43 }
44
45 fn write_record(&mut self, record: &GdsRecord) -> GdsResult<()> {
47 self.write_record_header(record)?;
49 self.write_record_content(record)?;
50 Ok(())
51 }
52
53 fn write_record_header(&mut self, record: &GdsRecord) -> GdsResult<()> {
54 let gds_strlen = |s: &str| -> usize { s.len() + s.len() % 2 };
56 use GdsDataType::{BitArray, F64, I16, I32, NoData, Str};
58 let (rtype, dtype, len) = match record {
59 GdsRecord::Header { .. } => (GdsRecordType::Header, I16, 2),
61 GdsRecord::BgnLib { .. } => (GdsRecordType::BgnLib, I16, 24),
62 GdsRecord::LibName(s) => (GdsRecordType::LibName, Str, gds_strlen(s)),
63 GdsRecord::Units(_, _) => (GdsRecordType::Units, F64, 16),
64 GdsRecord::EndLib => (GdsRecordType::EndLib, NoData, 0),
65
66 GdsRecord::BgnStruct { .. } => (GdsRecordType::BgnStruct, I16, 24),
68 GdsRecord::StructName(s) => (GdsRecordType::StructName, Str, gds_strlen(s)),
69 GdsRecord::StructRefName(s) => (GdsRecordType::StructRefName, Str, gds_strlen(s)),
70 GdsRecord::EndStruct => (GdsRecordType::EndStruct, NoData, 0),
71
72 GdsRecord::Boundary => (GdsRecordType::Boundary, NoData, 0),
74 GdsRecord::Path => (GdsRecordType::Path, NoData, 0),
75 GdsRecord::StructRef => (GdsRecordType::StructRef, NoData, 0),
76 GdsRecord::ArrayRef => (GdsRecordType::ArrayRef, NoData, 0),
77 GdsRecord::Text => (GdsRecordType::Text, NoData, 0),
78 GdsRecord::Layer(_) => (GdsRecordType::Layer, I16, 2),
79 GdsRecord::DataType(_) => (GdsRecordType::DataType, I16, 2),
80 GdsRecord::Width(_) => (GdsRecordType::Width, I32, 4),
81 GdsRecord::Xy(d) => (GdsRecordType::Xy, I32, 4 * d.len()),
82 GdsRecord::EndElement => (GdsRecordType::EndElement, NoData, 0),
83
84 GdsRecord::ColRow { .. } => (GdsRecordType::ColRow, I16, 4),
86 GdsRecord::Node => (GdsRecordType::Node, NoData, 0),
87 GdsRecord::TextType(_) => (GdsRecordType::TextType, I16, 2),
88 GdsRecord::Presentation(_, _) => (GdsRecordType::Presentation, BitArray, 2),
89 GdsRecord::String(s) => (GdsRecordType::String, Str, gds_strlen(s)),
90 GdsRecord::Strans(_, _) => (GdsRecordType::Strans, BitArray, 2),
91 GdsRecord::Mag(_) => (GdsRecordType::Mag, F64, 8),
92 GdsRecord::Angle(_) => (GdsRecordType::Angle, F64, 8),
93 GdsRecord::RefLibs(s) => (GdsRecordType::RefLibs, Str, gds_strlen(s)),
94 GdsRecord::Fonts(s) => (GdsRecordType::Fonts, Str, gds_strlen(s)),
95 GdsRecord::PathType(_) => (GdsRecordType::PathType, I16, 2),
96 GdsRecord::Generations(_) => (GdsRecordType::Generations, I16, 2),
97 GdsRecord::AttrTable(s) => (GdsRecordType::AttrTable, Str, gds_strlen(s)),
98 GdsRecord::ElemFlags(_, _) => (GdsRecordType::ElemFlags, BitArray, 2),
99 GdsRecord::Nodetype(_) => (GdsRecordType::Nodetype, I16, 2),
100 GdsRecord::PropAttr(_) => (GdsRecordType::PropAttr, I16, 2),
101 GdsRecord::PropValue(s) => (GdsRecordType::PropValue, Str, gds_strlen(s)),
102 GdsRecord::Box => (GdsRecordType::Box, NoData, 0),
103 GdsRecord::BoxType(_) => (GdsRecordType::BoxType, I16, 2),
104 GdsRecord::Plex(_) => (GdsRecordType::Plex, I32, 4),
105 GdsRecord::BeginExtn(_) => (GdsRecordType::BeginExtn, I32, 4),
106 GdsRecord::EndExtn(_) => (GdsRecordType::EndExtn, I32, 4),
107 GdsRecord::TapeNum(_) => (GdsRecordType::TapeNum, I16, 2),
108 GdsRecord::TapeCode(_) => (GdsRecordType::TapeCode, I16, 12),
109 GdsRecord::Format(_) => (GdsRecordType::Format, I16, 2),
110 GdsRecord::Mask(s) => (GdsRecordType::Mask, Str, gds_strlen(s)),
111 GdsRecord::EndMasks => (GdsRecordType::EndMasks, NoData, 0),
112 GdsRecord::LibDirSize(_) => (GdsRecordType::LibDirSize, I16, 2),
113 GdsRecord::SrfName(s) => (GdsRecordType::SrfName, Str, gds_strlen(s)),
114 GdsRecord::LibSecur(_) => (GdsRecordType::LibSecur, I16, 2),
115 };
116 match u16::try_from(len + 4) {
119 Ok(val) => self.dest.write_u16::<BigEndian>(val)?,
120 Err(_) => return Err(GdsError::RecordLen(len)),
121 };
122 self.dest.write_u8(rtype as u8)?;
123 self.dest.write_u8(dtype as u8)?;
124 Ok(())
125 }
126
127 fn write_record_content(&mut self, record: &GdsRecord) -> GdsResult<()> {
128 match record {
131 GdsRecord::EndLib
133 | GdsRecord::EndStruct
134 | GdsRecord::Boundary
135 | GdsRecord::Path
136 | GdsRecord::StructRef
137 | GdsRecord::ArrayRef
138 | GdsRecord::Text
139 | GdsRecord::EndElement
140 | GdsRecord::Node
141 | GdsRecord::Box
142 | GdsRecord::EndMasks => (),
143
144 GdsRecord::Presentation(d0, d1)
146 | GdsRecord::Strans(d0, d1)
147 | GdsRecord::ElemFlags(d0, d1) => {
148 self.dest.write_u8(*d0)?;
149 self.dest.write_u8(*d1)?;
150 }
151 GdsRecord::Header { version: d }
153 | GdsRecord::Layer(d)
154 | GdsRecord::DataType(d)
155 | GdsRecord::TextType(d)
156 | GdsRecord::PathType(d)
157 | GdsRecord::Generations(d)
158 | GdsRecord::Nodetype(d)
159 | GdsRecord::PropAttr(d)
160 | GdsRecord::BoxType(d)
161 | GdsRecord::TapeNum(d)
162 | GdsRecord::Format(d)
163 | GdsRecord::LibDirSize(d)
164 | GdsRecord::LibSecur(d) => self.dest.write_i16::<BigEndian>(*d)?,
165
166 GdsRecord::Width(d)
168 | GdsRecord::Plex(d)
169 | GdsRecord::BeginExtn(d)
170 | GdsRecord::EndExtn(d) => self.dest.write_i32::<BigEndian>(*d)?,
171 GdsRecord::Mag(d) | GdsRecord::Angle(d) => {
173 self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d))?
174 }
175 GdsRecord::Units(d0, d1) => {
177 self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d0))?;
178 self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d1))?;
179 }
180 GdsRecord::ColRow { cols, rows } => {
181 self.dest.write_i16::<BigEndian>(*cols)?;
182 self.dest.write_i16::<BigEndian>(*rows)?;
183 }
184 GdsRecord::BgnLib { dates: d } | GdsRecord::BgnStruct { dates: d } => {
186 for val in d.iter() {
187 self.dest.write_i16::<BigEndian>(*val)?;
188 }
189 }
190 GdsRecord::TapeCode(d) => {
192 for val in d.iter() {
193 self.dest.write_i16::<BigEndian>(*val)?;
194 }
195 }
196 GdsRecord::Xy(d) => {
197 for val in d.iter() {
198 self.dest.write_i32::<BigEndian>(*val)?;
199 }
200 }
201 GdsRecord::LibName(s)
203 | GdsRecord::StructName(s)
204 | GdsRecord::StructRefName(s)
205 | GdsRecord::String(s)
206 | GdsRecord::RefLibs(s)
207 | GdsRecord::Fonts(s)
208 | GdsRecord::AttrTable(s)
209 | GdsRecord::PropValue(s)
210 | GdsRecord::Mask(s)
211 | GdsRecord::SrfName(s) => {
212 for b in s.as_bytes() {
213 self.dest.write_u8(*b)?;
214 }
215 if s.len() % 2 != 0 {
216 self.dest.write_u8(0x00)?;
218 }
219 }
220 };
221 Ok(())
222 }
223}
224
225impl Encode for GdsWriter<'_> {
229 fn encode_record(&mut self, record: GdsRecord) -> GdsResult<()> {
230 self.write_record(&record)
231 }
232 fn encode_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> {
233 self.write_records(records)
234 }
235}
236
237trait Encode {
247 fn encode_record(&mut self, record: GdsRecord) -> GdsResult<()>;
250 fn encode_records(&mut self, records: &[GdsRecord]) -> GdsResult<()>;
252
253 fn encode_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
256 self.encode_records(&[
258 GdsRecord::Header {
259 version: lib.version,
260 },
261 GdsRecord::BgnLib {
262 dates: lib.dates.encode().to_vec(),
263 },
264 GdsRecord::LibName(lib.name.clone()),
265 GdsRecord::Units(lib.units.0, lib.units.1),
266 ])?;
267 for strukt in lib.structs.iter() {
269 self.encode_struct(strukt)?;
270 }
271 self.encode_record(GdsRecord::EndLib)?;
273 Ok(())
274 }
275
276 fn encode_struct(&mut self, strukt: &GdsStruct) -> GdsResult<()> {
278 self.encode_records(&[
280 GdsRecord::BgnStruct {
281 dates: strukt.dates.encode().to_vec(),
282 },
283 GdsRecord::StructName(strukt.name.clone()),
284 ])?;
285 for elem in strukt.elems.iter() {
287 self.encode_element(elem)?;
288 }
289 self.encode_record(GdsRecord::EndStruct)?;
291 Ok(())
292 }
293
294 fn encode_element(&mut self, elem: &GdsElement) -> GdsResult<()> {
296 use GdsElement::*;
297 match elem {
298 GdsBoundary(e) => self.encode_boundary(e)?,
299 GdsPath(e) => self.encode_path(e)?,
300 GdsStructRef(e) => self.encode_struct_ref(e)?,
301 GdsArrayRef(e) => self.encode_array_ref(e)?,
302 GdsTextElem(e) => self.encode_text_elem(e)?,
303 GdsNode(e) => self.encode_node(e)?,
304 GdsBox(e) => self.encode_box(e)?,
305 };
306 Ok(())
307 }
308
309 fn encode_path(&mut self, path: &GdsPath) -> GdsResult<()> {
311 self.encode_record(GdsRecord::Path)?;
312 if let Some(ref e) = path.elflags {
313 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
314 }
315 if let Some(ref e) = path.plex {
316 self.encode_record(GdsRecord::Plex(e.0))?;
317 }
318 self.encode_record(GdsRecord::Layer(path.layer))?;
319 self.encode_record(GdsRecord::DataType(path.datatype))?;
320 if let Some(ref e) = path.path_type {
321 self.encode_record(GdsRecord::PathType(*e))?;
322 }
323 if let Some(ref e) = path.width {
324 self.encode_record(GdsRecord::Width(*e))?;
325 }
326 if let Some(ref e) = path.begin_extn {
327 self.encode_record(GdsRecord::BeginExtn(*e))?;
328 }
329 if let Some(ref e) = path.end_extn {
330 self.encode_record(GdsRecord::EndExtn(*e))?;
331 }
332 self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&path.xy)))?;
333 for prop in path.properties.iter() {
334 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
335 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
336 }
337 self.encode_record(GdsRecord::EndElement)?;
338 Ok(())
339 }
340
341 fn encode_boundary(&mut self, boundary: &GdsBoundary) -> GdsResult<()> {
343 self.encode_record(GdsRecord::Boundary)?;
344 if let Some(ref e) = boundary.elflags {
345 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
346 }
347 if let Some(ref e) = boundary.plex {
348 self.encode_record(GdsRecord::Plex(e.0))?;
349 }
350 self.encode_record(GdsRecord::Layer(boundary.layer))?;
351 self.encode_record(GdsRecord::DataType(boundary.datatype))?;
352 self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&boundary.xy)))?;
353 for prop in boundary.properties.iter() {
354 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
355 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
356 }
357 self.encode_record(GdsRecord::EndElement)?;
358 Ok(())
359 }
360
361 fn encode_struct_ref(&mut self, sref: &GdsStructRef) -> GdsResult<()> {
363 self.encode_record(GdsRecord::StructRef)?;
364 if let Some(ref e) = sref.elflags {
365 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
366 }
367 if let Some(ref e) = sref.plex {
368 self.encode_record(GdsRecord::Plex(e.0))?;
369 }
370 self.encode_record(GdsRecord::StructRefName(sref.name.clone()))?;
371 if let Some(ref e) = sref.strans {
372 self.encode_strans(e)?;
373 }
374 self.encode_record(GdsRecord::Xy(GdsPoint::flatten(&sref.xy)))?;
375 for prop in sref.properties.iter() {
376 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
377 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
378 }
379 self.encode_record(GdsRecord::EndElement)?;
380 Ok(())
381 }
382
383 fn encode_array_ref(&mut self, aref: &GdsArrayRef) -> GdsResult<()> {
385 self.encode_record(GdsRecord::ArrayRef)?;
386 if let Some(ref e) = aref.elflags {
387 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
388 }
389 if let Some(ref e) = aref.plex {
390 self.encode_record(GdsRecord::Plex(e.0))?;
391 }
392 self.encode_record(GdsRecord::StructRefName(aref.name.clone()))?;
393 if let Some(ref e) = aref.strans {
394 self.encode_strans(e)?;
395 }
396 self.encode_record(GdsRecord::ColRow {
397 cols: aref.cols,
398 rows: aref.rows,
399 })?;
400 let mut xy = GdsPoint::flatten(&aref.xy[0]);
401 xy.extend(GdsPoint::flatten(&aref.xy[1]));
402 xy.extend(GdsPoint::flatten(&aref.xy[2]));
403 self.encode_record(GdsRecord::Xy(xy))?;
404 for prop in aref.properties.iter() {
405 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
406 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
407 }
408 self.encode_record(GdsRecord::EndElement)?;
409 Ok(())
410 }
411
412 fn encode_text_elem(&mut self, text: &GdsTextElem) -> GdsResult<()> {
414 self.encode_record(GdsRecord::Text)?;
415 if let Some(ref e) = text.elflags {
416 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
417 }
418 if let Some(ref e) = text.plex {
419 self.encode_record(GdsRecord::Plex(e.0))?;
420 }
421 self.encode_record(GdsRecord::Layer(text.layer))?;
422 self.encode_record(GdsRecord::TextType(text.texttype))?;
423 if let Some(ref e) = text.presentation {
424 self.encode_record(GdsRecord::Presentation(e.0, e.1))?;
425 }
426 if let Some(ref e) = text.path_type {
427 self.encode_record(GdsRecord::PathType(*e))?;
428 }
429 if let Some(ref e) = text.width {
430 self.encode_record(GdsRecord::Width(*e))?;
431 }
432 if let Some(ref e) = text.strans {
433 self.encode_strans(e)?;
434 }
435 self.encode_record(GdsRecord::Xy(GdsPoint::flatten(&text.xy)))?;
436 self.encode_record(GdsRecord::String(text.string.clone()))?;
437 for prop in text.properties.iter() {
438 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
439 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
440 }
441 self.encode_record(GdsRecord::EndElement)?;
442 Ok(())
443 }
444
445 fn encode_node(&mut self, node: &GdsNode) -> GdsResult<()> {
447 self.encode_record(GdsRecord::Node)?;
448 if let Some(ref e) = node.elflags {
449 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
450 }
451 if let Some(ref e) = node.plex {
452 self.encode_record(GdsRecord::Plex(e.0))?;
453 }
454 self.encode_record(GdsRecord::Layer(node.layer))?;
455 self.encode_record(GdsRecord::Nodetype(node.nodetype))?;
456 self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(&node.xy)))?;
457 for prop in node.properties.iter() {
458 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
459 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
460 }
461 self.encode_record(GdsRecord::EndElement)?;
462 Ok(())
463 }
464
465 fn encode_box(&mut self, box_: &GdsBox) -> GdsResult<()> {
467 self.encode_record(GdsRecord::Box)?;
468 if let Some(ref e) = box_.elflags {
469 self.encode_record(GdsRecord::ElemFlags(e.0, e.1))?;
470 }
471 if let Some(ref e) = box_.plex {
472 self.encode_record(GdsRecord::Plex(e.0))?;
473 }
474 self.encode_record(GdsRecord::Layer(box_.layer))?;
475 self.encode_record(GdsRecord::BoxType(box_.boxtype))?;
476 self.encode_record(GdsRecord::Xy(GdsPoint::flatten_vec(box_.xy.as_ref())))?;
477 for prop in box_.properties.iter() {
478 self.encode_record(GdsRecord::PropAttr(prop.attr))?;
479 self.encode_record(GdsRecord::PropValue(prop.value.clone()))?;
480 }
481 self.encode_record(GdsRecord::EndElement)?;
482 Ok(())
483 }
484
485 fn encode_strans(&mut self, strans: &GdsStrans) -> GdsResult<()> {
487 self.encode_record(GdsRecord::Strans(
488 (strans.reflected as u8) << 7,
489 ((strans.abs_mag as u8) << 2) | ((strans.abs_angle as u8) << 1),
490 ))?;
491 if let Some(ref e) = strans.mag {
492 self.encode_record(GdsRecord::Mag(*e))?;
493 }
494 if let Some(ref e) = strans.angle {
495 self.encode_record(GdsRecord::Angle(*e))?;
496 }
497 Ok(())
498 }
499}
500
501impl GdsDateTimes {
502 pub fn encode(&self) -> [i16; 12] {
504 [
505 self.modified.date().year() as i16,
506 self.modified.date().month() as i16,
507 self.modified.date().day() as i16,
508 self.modified.time().hour() as i16,
509 self.modified.time().minute() as i16,
510 self.modified.time().second() as i16,
511 self.accessed.date().year() as i16,
512 self.accessed.date().month() as i16,
513 self.accessed.date().day() as i16,
514 self.accessed.time().hour() as i16,
515 self.accessed.time().minute() as i16,
516 self.accessed.time().second() as i16,
517 ]
518 }
519}