1use std::collections::HashMap;
4use std::hash::Hash;
5
6use crate::GdsLayer;
7use arcstr::ArcStr;
8use geometry::prelude::Contains;
9use layir::{Cell, Direction, Element, Instance, LibraryBuilder, Port};
10use thiserror::Error;
11
12pub trait FromGds: Sized {
14 fn from_gds(layer: GdsLayer) -> Option<Self>;
18 fn from_gds_pin(layer: GdsLayer) -> Option<Self>;
23 fn from_gds_label(layer: GdsLayer) -> Option<Self>;
28}
29
30#[derive(Error, Debug)]
31pub enum FromGdsError {
32 #[error("no layer mapping for layer {layer} in cell `{cell}`")]
33 NoLayerMapping { cell: ArcStr, layer: GdsLayer },
34 #[error("pin with multiple labels: `{label1}`, `{label2}` in cell `{cell}`")]
35 PinWithMultipleLabels {
36 cell: ArcStr,
37 label1: ArcStr,
38 label2: ArcStr,
39 },
40 #[error("pin with no label in cell `{cell}`")]
41 PinWithNoLabel { cell: ArcStr },
42 #[error("error building LayIR library")]
43 BuildError(#[from] layir::BuildError),
44}
45
46pub fn from_gds<L: FromGds + Hash + Eq + Clone>(
48 lib: &layir::Library<GdsLayer>,
49) -> Result<layir::Library<L>, FromGdsError> {
50 let mut olib = LibraryBuilder::<L>::new();
51 let cells = lib.topological_order();
52 for cell in cells {
53 let cell = lib.cell(cell);
54 let mut ocell = Cell::new(cell.name());
55 for elt in cell.elements() {
56 let layer = *elt.layer();
57 let l = L::from_gds(layer).ok_or_else(|| FromGdsError::NoLayerMapping {
58 cell: cell.name().clone(),
59 layer,
60 })?;
61 ocell.add_element(elt.with_layer(l));
62 }
63 for (_, inst) in cell.instances() {
64 let name = lib.cell(inst.child()).name();
65 let child_id = olib.cell_id_named(name);
66 ocell.add_instance(Instance::with_transformation(
67 child_id,
68 inst.name(),
69 inst.transformation(),
70 ));
71 }
72 for (name, oport) in cell.ports() {
73 let port = oport.map_layer(|layer| L::from_gds(*layer).unwrap());
74 ocell.add_port(name, port);
75 }
76 let mut pin_correspondences: HashMap<L, (Vec<_>, Vec<_>)> = HashMap::new();
77 for elt in cell.elements() {
78 match elt {
79 Element::Shape(s) => {
80 if let Some(layer) = L::from_gds_pin(*s.layer()) {
81 let entry = pin_correspondences.entry(layer.clone()).or_default();
82 entry.0.push(s.with_layer(layer));
83 }
84 }
85 Element::Text(t) => {
86 if let Some(layer) =
87 L::from_gds_pin(*t.layer()).or_else(|| L::from_gds_label(*t.layer()))
88 {
89 let entry = pin_correspondences.entry(layer.clone()).or_default();
90 entry.1.push(t.with_layer(layer));
91 }
92 }
93 }
94 }
95 for (_, (shapes, texts)) in pin_correspondences {
96 for shape in shapes {
97 let mut name: Option<ArcStr> = None;
98 let mut pin_texts = Vec::new();
99 for text in texts.iter() {
100 if shape
101 .shape()
102 .contains(&text.transformation().offset_point())
103 .intersects()
104 {
105 if let Some(ref name) = name
107 && name != text.text()
108 {
109 return Err(FromGdsError::PinWithMultipleLabels {
110 cell: cell.name().clone(),
111 label1: name.clone(),
112 label2: text.text().clone(),
113 });
114 }
115 name = Some(text.text().clone());
116 pin_texts.push(text.clone());
117 }
118 }
119
120 if let Some(name) = name {
126 if ocell.try_port(&name).is_none() {
127 ocell.add_port(&name, Port::new(Direction::InOut));
128 }
129 let port = ocell.port_mut(&name);
130 port.add_element(shape);
131 for text in pin_texts {
132 port.add_element(text);
136 }
137 }
138 }
139 }
140 olib.add_cell(ocell);
141 }
142
143 Ok(olib.build()?)
144}