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 let file = BufWriter::new(File::create(fname)?);
16 Ok(Self::new(file))
17 }
18
19 pub fn new(dest: impl Write + 'wr) -> Self {
21 Self {
22 dest: Box::new(dest),
23 }
24 }
25
26 pub fn write_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
28 self.encode_lib(lib)
31 }
32
33 fn write_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> {
35 for r in records {
36 self.write_record(r)?;
37 }
38 Ok(())
39 }
40
41 fn write_record(&mut self, record: &GdsRecord) -> GdsResult<()> {
43 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 let gds_strlen = |s: &str| -> usize { s.len() + s.len() % 2 };
52 use GdsDataType::{BitArray, F64, I16, I32, NoData, Str};
54 let (rtype, dtype, len) = match record {
55 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 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 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 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 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 match record {
127 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 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 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 GdsRecord::Width(d)
164 | GdsRecord::Plex(d)
165 | GdsRecord::BeginExtn(d)
166 | GdsRecord::EndExtn(d) => self.dest.write_i32::<BigEndian>(*d)?,
167 GdsRecord::Mag(d) | GdsRecord::Angle(d) => {
169 self.dest.write_u64::<BigEndian>(GdsFloat64::encode(*d))?
170 }
171 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 GdsRecord::BgnLib { dates: d } | GdsRecord::BgnStruct { dates: d } => {
182 for val in d.iter() {
183 self.dest.write_i16::<BigEndian>(*val)?;
184 }
185 }
186 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 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 self.dest.write_u8(0x00)?;
214 }
215 }
216 };
217 Ok(())
218 }
219}
220
221impl 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
233trait Encode {
243 fn encode_record(&mut self, record: GdsRecord) -> GdsResult<()>;
246 fn encode_records(&mut self, records: &[GdsRecord]) -> GdsResult<()>;
248
249 fn encode_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> {
252 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 for strukt in lib.structs.iter() {
265 self.encode_struct(strukt)?;
266 }
267 self.encode_record(GdsRecord::EndLib)?;
269 Ok(())
270 }
271
272 fn encode_struct(&mut self, strukt: &GdsStruct) -> GdsResult<()> {
274 self.encode_records(&[
276 GdsRecord::BgnStruct {
277 dates: strukt.dates.encode().to_vec(),
278 },
279 GdsRecord::StructName(strukt.name.clone()),
280 ])?;
281 for elem in strukt.elems.iter() {
283 self.encode_element(elem)?;
284 }
285 self.encode_record(GdsRecord::EndStruct)?;
287 Ok(())
288 }
289
290 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 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 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 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 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 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 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 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 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 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}