1#![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
104use read::{GdsParser, GdsScanner, GdsStructScan};
106pub use ser::{SerdeFile, SerializationFormat};
107use write::GdsWriter;
108
109#[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, EndStruct,
123 Boundary,
124 Path,
125 StructRef,
126 ArrayRef,
127 Text,
128 Layer,
129 DataType,
130 Width,
131 Xy,
132 EndElement,
133 StructRefName, ColRow,
135 TextNode, Node,
137 TextType,
138 Presentation,
139 Spacing, String,
141 Strans,
142 Mag,
143 Angle,
144 Uinteger, Ustring, RefLibs,
147 Fonts,
148 PathType,
149 Generations,
150 AttrTable,
151 StypTable, StrType, ElemFlags,
154 ElemKey, LinkType, LinkKeys, Nodetype,
158 PropAttr,
159 PropValue,
160 Box,
161 BoxType,
162 Plex,
163 BeginExtn, EndExtn, TapeNum,
166 TapeCode,
167 StrClass, Reserved, Format,
170 Mask,
171 EndMasks,
172 LibDirSize,
173 SrfName,
174 LibSecur,
175}
176
177impl GdsRecordType {
178 pub fn valid(&self) -> bool {
183 match self {
184 Self::TextNode | Self::Spacing | Self::Uinteger | Self::Ustring | Self::StypTable | Self::StrType | Self::ElemKey | Self::LinkType | Self::LinkKeys | Self::StrClass | Self::Reserved => false,
196 _ => true,
197 }
198 }
199}
200
201#[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#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
221pub struct GdsRecordHeader {
222 rtype: GdsRecordType,
223 dtype: GdsDataType,
224 len: u16,
225}
226
227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234#[allow(missing_docs)]
235pub enum GdsRecord {
236 Header { version: i16 },
237 BgnLib { dates: Vec<i16> }, LibName(ArcStr),
239 Units(f64, f64),
240 EndLib,
241 BgnStruct { dates: Vec<i16> }, StructName(ArcStr), StructRefName(ArcStr), 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>), Format(i16),
280 Mask(ArcStr),
281 EndMasks,
282 LibDirSize(i16),
283 SrfName(ArcStr),
284 LibSecur(i16),
285}
286
287pub struct GdsFloat64;
290
291impl GdsFloat64 {
292 pub fn decode(val: u64) -> f64 {
294 let neg = (val & 0x8000_0000_0000_0000) != 0;
296 let exp: i32 = ((val & 0x7F00_0000_0000_0000) >> (8 * 7)) as i32 - 64;
298 let mantissa: u64 = val & 0x00FF_FFFF_FFFF_FFFF;
300 let mantissa: f64 = mantissa as f64 / 2f64.powi(8 * 7);
302 if neg {
304 -mantissa * 16f64.powi(exp)
305 } else {
306 mantissa * 16f64.powi(exp)
307 }
308 }
309 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#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
333pub struct Unsupported;
334
335#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)]
340pub struct GdsStrans {
341 pub reflected: bool,
346 pub abs_mag: bool,
348 pub abs_angle: bool,
350
351 #[serde(default, skip_serializing_if = "Option::is_none")]
354 pub mag: Option<f64>,
355 #[serde(default, skip_serializing_if = "Option::is_none")]
357 pub angle: Option<f64>,
358}
359
360#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
365pub struct GdsPresentation(u8, u8);
366
367#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
372pub struct GdsElemFlags(u8, u8);
373
374#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
380pub struct GdsPlex(i32);
381
382#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
398pub struct GdsUnits(f64, f64);
399
400impl GdsUnits {
401 pub const fn new(num1: f64, num2: f64) -> Self {
403 Self(num1, num2)
404 }
405 pub const fn db_unit(&self) -> f64 {
407 self.1
408 }
409 pub const fn user_unit(&self) -> f64 {
411 self.0 / self.1
412 }
413}
414
415impl Default for GdsUnits {
416 fn default() -> Self {
420 Self(1e-3, 1e-9)
421 }
422}
423
424#[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 pub fn new(x: i32, y: i32) -> Self {
438 GdsPoint { x, y }
439 }
440
441 pub fn vec(pts: &[(i32, i32)]) -> Vec<Self> {
443 pts.iter().map(|pt| Self::new(pt.0, pt.1)).collect()
444 }
445
446 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 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 fn flatten(&self) -> Vec<i32> {
478 vec![self.x, self.y]
479 }
480
481 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#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
502pub enum GdsFormatType {
503 Archive,
505 Filtered(Vec<Unsupported>),
507}
508
509#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)]
516pub struct GdsProperty {
517 pub attr: i16,
519 pub value: ArcStr,
521}
522
523#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
530#[builder(pattern = "owned", setter(into), private)]
531#[allow(missing_docs)]
532pub struct GdsPath {
533 pub layer: i16,
536 pub datatype: i16,
538 pub xy: Vec<GdsPoint>,
540
541 #[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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
578#[builder(pattern = "owned", setter(into), private)]
579#[allow(missing_docs)]
580pub struct GdsBoundary {
581 pub layer: i16,
584 pub datatype: i16,
586 pub xy: Vec<GdsPoint>,
588
589 #[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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
613#[builder(pattern = "owned", setter(into), private)]
614#[allow(missing_docs)]
615pub struct GdsStructRef {
616 pub name: ArcStr,
619 pub xy: GdsPoint,
621
622 #[serde(default, skip_serializing_if = "Option::is_none")]
624 #[builder(default, setter(strip_option))]
625 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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
647#[builder(pattern = "owned", setter(into), private)]
648#[allow(missing_docs)]
649pub struct GdsArrayRef {
650 pub name: ArcStr,
653 pub xy: [GdsPoint; 3],
655 pub cols: i16,
657 pub rows: i16,
659 #[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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
683#[builder(pattern = "owned", setter(into), private)]
684#[allow(missing_docs)]
685pub struct GdsTextElem {
686 pub string: ArcStr,
689 pub layer: i16,
691 pub texttype: i16,
693 pub xy: GdsPoint,
695
696 #[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 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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
728#[builder(pattern = "owned", setter(into), private)]
729#[allow(missing_docs)]
730pub struct GdsNode {
731 pub layer: i16,
734 pub nodetype: i16,
736 pub xy: Vec<GdsPoint>,
738
739 #[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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
758#[builder(pattern = "owned", setter(into), private)]
759#[allow(missing_docs)]
760pub struct GdsBox {
761 pub layer: i16,
764 pub boxtype: i16,
766 pub xy: [GdsPoint; 5],
768
769 #[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#[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#[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#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
822pub struct GdsDateTimes {
823 pub modified: NaiveDateTime,
825 pub accessed: NaiveDateTime,
827}
828
829impl Default for GdsDateTimes {
830 fn default() -> Self {
832 let now = Utc::now().naive_utc();
833 Self {
834 modified: now,
835 accessed: now,
836 }
837 }
838}
839
840#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
857#[builder(pattern = "owned", setter(into), private)]
858pub struct GdsStruct {
859 pub name: ArcStr,
861 pub dates: GdsDateTimes,
863 pub elems: Vec<GdsElement>,
865}
866impl GdsStruct {
867 pub fn new(name: impl Into<ArcStr>) -> Self {
869 Self {
870 name: name.into(),
871 ..Default::default()
872 }
873 }
874 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#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq)]
910#[builder(pattern = "owned", setter(into), private)]
911#[allow(missing_docs)]
912pub struct GdsLibrary {
913 pub name: ArcStr,
916 pub version: i16,
918 pub dates: GdsDateTimes,
920 pub units: GdsUnits,
922 pub structs: Vec<GdsStruct>,
924
925 #[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 pub fn new(name: impl Into<ArcStr>) -> Self {
955 Self {
956 name: name.into(),
957 version: 3,
958 ..Default::default()
959 }
960 }
961
962 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 pub fn load(fname: impl AsRef<Path>) -> GdsResult<GdsLibrary> {
974 GdsParser::open(fname)?.parse_lib()
976 }
977
978 pub fn from_bytes(bytes: Vec<u8>) -> GdsResult<GdsLibrary> {
980 GdsParser::from_bytes(bytes)?.parse_lib()
982 }
983
984 #[allow(dead_code)] fn scan(fname: impl AsRef<Path>) -> GdsResult<Vec<GdsStructScan>> {
989 GdsScanner::scan(fname)
990 }
991
992 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 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 pub fn write(&self, file: impl Write) -> GdsResult<()> {
1014 let mut wr = GdsWriter::new(file);
1015 wr.write_lib(self)
1016 }
1017}
1018
1019impl SerdeFile for GdsLibrary {}
1021impl SerdeFile for GdsStruct {}
1022
1023#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1033pub struct GdsLayerSpec {
1034 pub layer: i16,
1036 pub xtype: i16,
1038}
1039
1040pub trait HasLayer {
1042 fn layerspec(&self) -> GdsLayerSpec;
1044}
1045
1046impl GdsLayerSpec {
1047 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#[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
1099pub type GdsResult<T> = Result<T, GdsError>;
1101
1102#[derive(Debug, Clone)]
1107pub enum GdsError {
1108 RecordDecode(GdsRecordType, GdsDataType, u16),
1110 RecordLen(usize),
1112 InvalidDataType(u8),
1114 InvalidRecordType(u8),
1116 Unsupported(Option<GdsRecord>, Option<GdsContext>),
1118 #[allow(missing_docs)]
1120 Parse {
1121 msg: String,
1122 record: GdsRecord,
1123 recordnum: usize,
1124 bytepos: u64,
1125 ctx: Vec<GdsContext>,
1126 },
1127 Boxed(Arc<dyn Error + Send + Sync>),
1129 Str(String),
1131}
1132
1133impl std::fmt::Display for GdsError {
1134 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"))]
1170pub fn roundtrip(lib: &GdsLibrary) -> GdsResult<()> {
1172 use tempfile::tempfile;
1173
1174 let mut file = tempfile()?;
1176 lib.write(&mut file)?;
1177
1178 file.rewind()?;
1180 let mut bytes = Vec::new();
1181 file.read_to_end(&mut bytes)?;
1182 let lib2 = GdsLibrary::from_bytes(bytes)?;
1183
1184 assert_eq!(*lib, lib2);
1186 Ok(())
1187}