klayout-core 0.0.1

Core data model for klayout-rs: coordinates, shapes, cells, libraries
Documentation
//! Ports: typed connection points on a cell.
//!
//! `PortKindId` is opaque to core; the typed `PortKind` enum lives in the PDK
//! crate (generated by the `pdk!{}` macro). Core only needs to round-trip the
//! id and hash it deterministically.

use crate::coord::{Point, Trans};
use crate::layer::LayerIndex;
use smol_str::SmolStr;

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct PortKindId(pub u32);

impl PortKindId {
    pub const ANY: Self = Self(0);
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Angle90 {
    E = 0,
    N = 1,
    W = 2,
    S = 3,
}

impl Angle90 {
    pub fn degrees(self) -> i32 {
        (self as i32) * 90
    }

    pub fn rotate(self, by: crate::coord::Rot4) -> Angle90 {
        let s = self as u8;
        let r = by as u8;
        match (s + r) % 4 {
            0 => Angle90::E,
            1 => Angle90::N,
            2 => Angle90::W,
            _ => Angle90::S,
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Port {
    pub name: SmolStr,
    pub kind: PortKindId,
    pub center: Point,
    pub angle: Angle90,
    pub width: i64,
    pub layer: LayerIndex,
}

impl Port {
    pub fn new(
        name: impl Into<SmolStr>,
        layer: LayerIndex,
        center: Point,
        angle: Angle90,
        width: i64,
    ) -> Self {
        Self {
            name: name.into(),
            kind: PortKindId::ANY,
            center,
            angle,
            width,
            layer,
        }
    }

    pub fn with_kind(mut self, kind: PortKindId) -> Self {
        self.kind = kind;
        self
    }

    pub fn transform(&self, t: Trans) -> Port {
        Port {
            name: self.name.clone(),
            kind: self.kind,
            center: t.apply(self.center),
            angle: if t.mirror {
                // Mirror about X flips N<->S, leaves E/W alone, then rotation applies.
                let after_mirror = match self.angle {
                    Angle90::E => Angle90::E,
                    Angle90::N => Angle90::S,
                    Angle90::W => Angle90::W,
                    Angle90::S => Angle90::N,
                };
                after_mirror.rotate(t.rot)
            } else {
                self.angle.rotate(t.rot)
            },
            width: self.width,
            layer: self.layer,
        }
    }
}