klayout_lyp/
lib.rs

1use std::io::Read;
2
3use rgb::Rgb;
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
7#[serde(rename = "layer-properties")]
8pub struct KlayoutLayerProperties {
9    pub name: String,
10    #[serde(rename = "properties")]
11    #[serde(default)]
12    pub layers: Vec<LayerProperties>,
13    #[serde(rename = "custom-dither-pattern")]
14    #[serde(default)]
15    pub custom_dither_patterns: Vec<CustomDitherPattern>,
16    #[serde(rename = "custom-line-style")]
17    #[serde(default)]
18    pub custom_line_styles: Vec<CustomLineStyle>,
19}
20
21#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
22#[serde(rename = "properties")]
23#[serde(rename_all = "kebab-case")]
24pub struct LayerProperties {
25    pub name: String,
26    pub source: String,
27    #[serde(with = "lyp_rgb_format")]
28    pub frame_color: Rgb<u8>,
29    #[serde(with = "lyp_rgb_format")]
30    pub fill_color: Rgb<u8>,
31    pub frame_brightness: u8,
32    pub fill_brightness: u8,
33    pub dither_pattern: String,
34    pub line_style: String,
35    pub valid: bool,
36    pub visible: bool,
37    pub transparent: bool,
38    pub width: i32,
39    pub marked: bool,
40    pub xfill: bool,
41    pub animation: i32,
42}
43
44#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
45#[serde(rename = "custom-dither-pattern")]
46pub struct CustomDitherPattern {
47    pub pattern: DitherPattern,
48    pub order: i32,
49    pub name: String,
50}
51
52#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
53#[serde(rename = "pattern")]
54pub struct DitherPattern {
55    #[serde(rename = "line")]
56    pub lines: Vec<String>,
57}
58
59#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
60#[serde(rename = "custom-line-style")]
61pub struct CustomLineStyle {
62    pub pattern: String,
63    pub order: i32,
64    pub name: String,
65}
66
67pub fn from_str(lyp: &str) -> Result<KlayoutLayerProperties, serde_xml_rs::Error> {
68    serde_xml_rs::from_str(lyp)
69}
70
71pub fn from_reader<R: Read>(reader: R) -> Result<KlayoutLayerProperties, serde_xml_rs::Error> {
72    serde_xml_rs::from_reader(reader)
73}
74
75mod lyp_rgb_format {
76    use crate::*;
77    use serde::{Deserializer, Serializer};
78
79    pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Rgb<u8>, D::Error>
80    where
81        D: Deserializer<'de>,
82    {
83        let s = String::deserialize(deserializer)?;
84        let r = u8::from_str_radix(&s[1..3], 16).map_err(serde::de::Error::custom)?;
85        let g = u8::from_str_radix(&s[3..5], 16).map_err(serde::de::Error::custom)?;
86        let b = u8::from_str_radix(&s[5..7], 16).map_err(serde::de::Error::custom)?;
87
88        Ok(Rgb { r, g, b })
89    }
90
91    pub(crate) fn serialize<S>(value: &Rgb<u8>, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: Serializer,
94    {
95        String::serialize(&format!("#{}{}{}", value.r, value.g, value.b), serializer)
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::*;
102    const SKY130_LYP: &str =
103        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/examples/sky130.lyp"));
104
105    #[test]
106    fn parse_sky130_lyp() {
107        let lyp = from_str(SKY130_LYP).unwrap();
108        println!("{lyp:#?}");
109    }
110}