Skip to main content

altium_format/records/pcb/
class.rs

1//! PCB class definitions for organizing objects.
2//!
3//! Classes group related objects (components, nets, pads, etc.) for
4//! design rules, visibility control, and organization.
5
6use crate::types::ParameterCollection;
7
8/// The kind/type of class.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10#[repr(u8)]
11pub enum ClassKind {
12    /// Net class - groups nets for routing rules.
13    #[default]
14    Net = 0,
15    /// Component class - groups components.
16    Component = 1,
17    /// From-To class - groups from-to pairs.
18    FromTo = 2,
19    /// Pad class - groups pads.
20    Pad = 3,
21    /// Layer class - groups layers.
22    Layer = 4,
23    /// Differential pair class.
24    DifferentialPair = 5,
25    /// Design channel class.
26    DesignChannel = 6,
27    /// Polygon class - groups polygons.
28    Polygon = 7,
29    /// Structure class.
30    Structure = 8,
31    /// Unknown class kind.
32    Unknown(u8),
33}
34
35impl ClassKind {
36    /// Create from integer value.
37    pub fn from_int(value: i32) -> Self {
38        match value {
39            0 => ClassKind::Net,
40            1 => ClassKind::Component,
41            2 => ClassKind::FromTo,
42            3 => ClassKind::Pad,
43            4 => ClassKind::Layer,
44            5 => ClassKind::DifferentialPair,
45            6 => ClassKind::DesignChannel,
46            7 => ClassKind::Polygon,
47            8 => ClassKind::Structure,
48            v => ClassKind::Unknown(v as u8),
49        }
50    }
51
52    /// Convert to integer value.
53    pub fn to_int(self) -> i32 {
54        match self {
55            ClassKind::Net => 0,
56            ClassKind::Component => 1,
57            ClassKind::FromTo => 2,
58            ClassKind::Pad => 3,
59            ClassKind::Layer => 4,
60            ClassKind::DifferentialPair => 5,
61            ClassKind::DesignChannel => 6,
62            ClassKind::Polygon => 7,
63            ClassKind::Structure => 8,
64            ClassKind::Unknown(v) => v as i32,
65        }
66    }
67}
68
69/// A PCB class definition.
70///
71/// Classes are used to group related objects (nets, components, pads, etc.)
72/// for applying design rules, visibility settings, or organization.
73#[derive(Debug, Clone, Default)]
74pub struct PcbClass {
75    /// Class name.
76    pub name: String,
77    /// The kind of class (Net, Component, Pad, etc.).
78    pub kind: ClassKind,
79    /// Whether this is a superclass (contains all objects of this kind).
80    pub superclass: bool,
81    /// Whether this class was auto-generated.
82    pub auto_generated: bool,
83    /// Kind of auto-generation (0=none, 1=bottom side, 2=top side).
84    pub auto_generated_kind: i32,
85    /// Whether this is a schematic auto-generated cluster.
86    pub sch_auto_generated_cluster: bool,
87    /// Unique ID for the class.
88    pub unique_id: String,
89    /// Whether the class is selected.
90    pub selected: bool,
91    /// All parameters (for round-tripping unknown fields).
92    pub params: ParameterCollection,
93}
94
95impl PcbClass {
96    /// Create a new class with the given name and kind.
97    pub fn new(name: &str, kind: ClassKind) -> Self {
98        Self {
99            name: name.to_string(),
100            kind,
101            ..Default::default()
102        }
103    }
104
105    /// Parse a class from parameters.
106    pub fn from_params(params: &ParameterCollection) -> Self {
107        Self {
108            name: params
109                .get("NAME")
110                .map(|v| v.as_str().to_string())
111                .unwrap_or_default(),
112            kind: params
113                .get("KIND")
114                .map(|v| ClassKind::from_int(v.as_int_or(0)))
115                .unwrap_or_default(),
116            superclass: params
117                .get("SUPERCLASS")
118                .map(|v| v.as_bool_or(false))
119                .unwrap_or(false),
120            auto_generated: params
121                .get("AUTOGENERATEDCLASS")
122                .map(|v| v.as_bool_or(false))
123                .unwrap_or(false),
124            auto_generated_kind: params
125                .get("AUTOGENERATEDCLASSKIND")
126                .map(|v| v.as_int_or(0))
127                .unwrap_or(0),
128            sch_auto_generated_cluster: params
129                .get("SCHAUTOGENERATEDCLUSTER")
130                .map(|v| v.as_bool_or(false))
131                .unwrap_or(false),
132            unique_id: params
133                .get("UNIQUEID")
134                .map(|v| v.as_str().to_string())
135                .unwrap_or_default(),
136            selected: params
137                .get("SELECTED")
138                .map(|v| v.as_bool_or(false))
139                .unwrap_or(false),
140            params: params.clone(),
141        }
142    }
143
144    /// Export to parameters.
145    pub fn to_params(&self) -> ParameterCollection {
146        let mut params = self.params.clone();
147        params.add("NAME", &self.name);
148        params.add_int("KIND", self.kind.to_int());
149        params.add("SUPERCLASS", if self.superclass { "TRUE" } else { "FALSE" });
150        params.add(
151            "AUTOGENERATEDCLASS",
152            if self.auto_generated { "TRUE" } else { "FALSE" },
153        );
154        if self.auto_generated_kind != 0 {
155            params.add_int("AUTOGENERATEDCLASSKIND", self.auto_generated_kind);
156        }
157        params.add(
158            "SCHAUTOGENERATEDCLUSTER",
159            if self.sch_auto_generated_cluster {
160                "TRUE"
161            } else {
162                "FALSE"
163            },
164        );
165        if !self.unique_id.is_empty() {
166            params.add("UNIQUEID", &self.unique_id);
167        }
168        params.add("SELECTED", if self.selected { "TRUE" } else { "FALSE" });
169        params
170    }
171}