1use smol_str::SmolStr;
7use std::collections::HashMap;
8use std::num::NonZeroU16;
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub struct LayerIndex(NonZeroU16);
12
13impl LayerIndex {
14 pub(crate) fn from_slot(slot: usize) -> Self {
15 let n = u16::try_from(slot + 1)
20 .expect("LayerIndex arena exceeded u16::MAX (65535 layers)");
21 Self(NonZeroU16::new(n).expect("LayerIndex: slot+1 ≥ 1 by construction"))
22 }
23
24 pub(crate) fn slot(self) -> usize {
25 self.0.get() as usize - 1
26 }
27
28 pub fn raw(self) -> u16 {
29 self.0.get()
30 }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct LayerInfo {
35 pub layer: u16,
36 pub datatype: u16,
37 pub name: SmolStr,
38 pub purpose: Option<SmolStr>,
39}
40
41impl LayerInfo {
42 pub fn gds(layer: u16, datatype: u16) -> Self {
43 Self {
44 layer,
45 datatype,
46 name: SmolStr::default(),
47 purpose: None,
48 }
49 }
50
51 pub fn named(name: impl Into<SmolStr>, layer: u16, datatype: u16) -> Self {
52 Self {
53 layer,
54 datatype,
55 name: name.into(),
56 purpose: None,
57 }
58 }
59
60 pub fn key(&self) -> (u16, u16) {
61 (self.layer, self.datatype)
62 }
63}
64
65#[derive(Clone, Debug, Default)]
66pub struct LayerTable {
67 by_index: Vec<LayerInfo>,
68 by_gds: HashMap<(u16, u16), LayerIndex>,
69 by_name: HashMap<SmolStr, LayerIndex>,
70}
71
72impl LayerTable {
73 pub fn new() -> Self {
74 Self::default()
75 }
76
77 pub fn get_or_insert(&mut self, info: LayerInfo) -> LayerIndex {
78 if let Some(&idx) = self.by_gds.get(&info.key()) {
79 return idx;
80 }
81 let idx = LayerIndex::from_slot(self.by_index.len());
82 self.by_gds.insert(info.key(), idx);
83 if !info.name.is_empty() {
84 self.by_name.insert(info.name.clone(), idx);
85 }
86 self.by_index.push(info);
87 idx
88 }
89
90 pub fn info(&self, idx: LayerIndex) -> &LayerInfo {
91 &self.by_index[idx.slot()]
92 }
93
94 pub fn by_gds(&self, layer: u16, datatype: u16) -> Option<LayerIndex> {
95 self.by_gds.get(&(layer, datatype)).copied()
96 }
97
98 pub fn by_name(&self, name: &str) -> Option<LayerIndex> {
99 self.by_name.get(name).copied()
100 }
101
102 pub fn len(&self) -> usize {
103 self.by_index.len()
104 }
105
106 pub fn is_empty(&self) -> bool {
107 self.by_index.is_empty()
108 }
109
110 pub fn iter(&self) -> impl Iterator<Item = (LayerIndex, &LayerInfo)> {
111 self.by_index
112 .iter()
113 .enumerate()
114 .map(|(i, info)| (LayerIndex::from_slot(i), info))
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn dedup_by_gds() {
124 let mut t = LayerTable::new();
125 let a = t.get_or_insert(LayerInfo::named("WG", 1, 0));
126 let b = t.get_or_insert(LayerInfo::gds(1, 0));
127 assert_eq!(a, b);
128 assert_eq!(t.len(), 1);
129 assert_eq!(t.by_name("WG"), Some(a));
130 }
131}