Skip to main content

klayout_core/
port.rs

1//! Ports: typed connection points on a cell.
2//!
3//! `PortKindId` is opaque to core; the typed `PortKind` enum lives in the PDK
4//! crate (generated by the `pdk!{}` macro). Core only needs to round-trip the
5//! id and hash it deterministically.
6
7use crate::coord::{Point, Trans};
8use crate::layer::LayerIndex;
9use smol_str::SmolStr;
10
11#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
12pub struct PortKindId(pub u32);
13
14impl PortKindId {
15    pub const ANY: Self = Self(0);
16}
17
18#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
19#[repr(u8)]
20pub enum Angle90 {
21    E = 0,
22    N = 1,
23    W = 2,
24    S = 3,
25}
26
27impl Angle90 {
28    pub fn degrees(self) -> i32 {
29        (self as i32) * 90
30    }
31
32    pub fn rotate(self, by: crate::coord::Rot4) -> Angle90 {
33        let s = self as u8;
34        let r = by as u8;
35        match (s + r) % 4 {
36            0 => Angle90::E,
37            1 => Angle90::N,
38            2 => Angle90::W,
39            _ => Angle90::S,
40        }
41    }
42}
43
44#[derive(Clone, Debug, PartialEq, Eq, Hash)]
45pub struct Port {
46    pub name: SmolStr,
47    pub kind: PortKindId,
48    pub center: Point,
49    pub angle: Angle90,
50    pub width: i64,
51    pub layer: LayerIndex,
52}
53
54impl Port {
55    pub fn new(
56        name: impl Into<SmolStr>,
57        layer: LayerIndex,
58        center: Point,
59        angle: Angle90,
60        width: i64,
61    ) -> Self {
62        Self {
63            name: name.into(),
64            kind: PortKindId::ANY,
65            center,
66            angle,
67            width,
68            layer,
69        }
70    }
71
72    pub fn with_kind(mut self, kind: PortKindId) -> Self {
73        self.kind = kind;
74        self
75    }
76
77    pub fn transform(&self, t: Trans) -> Port {
78        Port {
79            name: self.name.clone(),
80            kind: self.kind,
81            center: t.apply(self.center),
82            angle: if t.mirror {
83                // Mirror about X flips N<->S, leaves E/W alone, then rotation applies.
84                let after_mirror = match self.angle {
85                    Angle90::E => Angle90::E,
86                    Angle90::N => Angle90::S,
87                    Angle90::W => Angle90::W,
88                    Angle90::S => Angle90::N,
89                };
90                after_mirror.rotate(t.rot)
91            } else {
92                self.angle.rotate(t.rot)
93            },
94            width: self.width,
95            layer: self.layer,
96        }
97    }
98}