1use super::common::FilterOp;
17use super::pattern::Pattern;
18
19#[derive(Debug, Clone)]
21pub struct Selector {
22 pub alternatives: Vec<SelectorChain>,
24}
25
26impl Selector {
27 pub fn single(chain: SelectorChain) -> Self {
29 Self {
30 alternatives: vec![chain],
31 }
32 }
33
34 pub fn any() -> Self {
36 Self::single(SelectorChain::single(SelectorSegment::any()))
37 }
38
39 pub fn is_empty(&self) -> bool {
41 self.alternatives.is_empty() || self.alternatives.iter().all(|c| c.segments.is_empty())
42 }
43}
44
45#[derive(Debug, Clone)]
47pub struct SelectorChain {
48 pub segments: Vec<SelectorSegment>,
50}
51
52impl SelectorChain {
53 pub fn single(segment: SelectorSegment) -> Self {
55 Self {
56 segments: vec![segment],
57 }
58 }
59
60 pub fn empty() -> Self {
62 Self { segments: vec![] }
63 }
64
65 pub fn push(&mut self, segment: SelectorSegment) {
67 self.segments.push(segment);
68 }
69}
70
71#[derive(Debug, Clone)]
73pub struct SelectorSegment {
74 pub matcher: RecordMatcher,
76 pub filters: Vec<PropertyFilter>,
78 pub pseudo: Vec<PseudoSelector>,
80 pub combinator: Option<Combinator>,
82}
83
84impl SelectorSegment {
85 pub fn any() -> Self {
87 Self {
88 matcher: RecordMatcher::Any,
89 filters: vec![],
90 pseudo: vec![],
91 combinator: None,
92 }
93 }
94
95 pub fn from_matcher(matcher: RecordMatcher) -> Self {
97 Self {
98 matcher,
99 filters: vec![],
100 pseudo: vec![],
101 combinator: None,
102 }
103 }
104
105 pub fn with_filter(mut self, filter: PropertyFilter) -> Self {
107 self.filters.push(filter);
108 self
109 }
110
111 pub fn with_pseudo(mut self, pseudo: PseudoSelector) -> Self {
113 self.pseudo.push(pseudo);
114 self
115 }
116
117 pub fn with_combinator(mut self, combinator: Combinator) -> Self {
119 self.combinator = Some(combinator);
120 self
121 }
122}
123
124#[derive(Debug, Clone)]
126pub enum RecordMatcher {
127 Any,
129
130 Type(RecordType),
132
133 Designator(Pattern),
135
136 PartNumber(Pattern),
138
139 Net(Pattern),
141
142 Value(Pattern),
144
145 Sheet(Pattern),
147
148 Pin {
150 component: Pattern,
152 pin: Pattern,
154 },
155
156 NetConnected {
158 net: Pattern,
160 target: NetConnectedTarget,
162 },
163
164 DesignatorWithValue {
166 designator: Pattern,
168 value: Pattern,
170 },
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum NetConnectedTarget {
176 Pins,
178 Components,
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
184pub enum RecordType {
185 Component,
186 Pin,
187 Wire,
188 NetLabel,
189 Port,
190 PowerObject,
191 Junction,
192 Label,
193 Rectangle,
194 Line,
195 Arc,
196 Ellipse,
197 Polygon,
198 Polyline,
199 Bezier,
200 Image,
201 Parameter,
202 Sheet,
203 Symbol,
204 Designator,
205 TextFrame,
206}
207
208impl RecordType {
209 pub fn try_parse(s: &str) -> Option<Self> {
211 match s.to_lowercase().as_str() {
212 "component" => Some(Self::Component),
213 "pin" => Some(Self::Pin),
214 "wire" => Some(Self::Wire),
215 "netlabel" | "net_label" => Some(Self::NetLabel),
216 "port" => Some(Self::Port),
217 "power" | "powerobject" | "power_object" => Some(Self::PowerObject),
218 "junction" => Some(Self::Junction),
219 "label" => Some(Self::Label),
220 "rectangle" | "rect" => Some(Self::Rectangle),
221 "line" => Some(Self::Line),
222 "arc" => Some(Self::Arc),
223 "ellipse" => Some(Self::Ellipse),
224 "polygon" => Some(Self::Polygon),
225 "polyline" => Some(Self::Polyline),
226 "bezier" => Some(Self::Bezier),
227 "image" => Some(Self::Image),
228 "parameter" | "param" => Some(Self::Parameter),
229 "sheet" => Some(Self::Sheet),
230 "symbol" => Some(Self::Symbol),
231 "designator" => Some(Self::Designator),
232 "textframe" | "text_frame" => Some(Self::TextFrame),
233 _ => None,
234 }
235 }
236
237 pub fn as_str(&self) -> &'static str {
239 match self {
240 Self::Component => "component",
241 Self::Pin => "pin",
242 Self::Wire => "wire",
243 Self::NetLabel => "netlabel",
244 Self::Port => "port",
245 Self::PowerObject => "power",
246 Self::Junction => "junction",
247 Self::Label => "label",
248 Self::Rectangle => "rectangle",
249 Self::Line => "line",
250 Self::Arc => "arc",
251 Self::Ellipse => "ellipse",
252 Self::Polygon => "polygon",
253 Self::Polyline => "polyline",
254 Self::Bezier => "bezier",
255 Self::Image => "image",
256 Self::Parameter => "parameter",
257 Self::Sheet => "sheet",
258 Self::Symbol => "symbol",
259 Self::Designator => "designator",
260 Self::TextFrame => "textframe",
261 }
262 }
263}
264
265#[derive(Debug, Clone)]
267pub struct PropertyFilter {
268 pub property: String,
270 pub operator: FilterOperator,
272 pub value: FilterValue,
274}
275
276impl PropertyFilter {
277 pub fn new(property: impl Into<String>, operator: FilterOperator, value: FilterValue) -> Self {
279 Self {
280 property: property.into(),
281 operator,
282 value,
283 }
284 }
285
286 pub fn eq(property: impl Into<String>, value: impl Into<String>) -> Self {
288 Self::new(
289 property,
290 FilterOperator::Equal,
291 FilterValue::String(value.into()),
292 )
293 }
294
295 pub fn matches(property: impl Into<String>, pattern: Pattern) -> Self {
297 Self::new(
298 property,
299 FilterOperator::Wildcard,
300 FilterValue::Pattern(pattern),
301 )
302 }
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307pub enum FilterOperator {
308 Equal,
310 NotEqual,
312 Wildcard,
314 StartsWith,
316 EndsWith,
318 Contains,
320 GreaterThan,
322 LessThan,
324 GreaterOrEqual,
326 LessOrEqual,
328}
329
330impl FilterOperator {
331 pub fn try_parse(s: &str) -> Option<Self> {
333 match s {
334 "=" => Some(Self::Equal),
335 "!=" => Some(Self::NotEqual),
336 "~=" => Some(Self::Wildcard),
337 "^=" => Some(Self::StartsWith),
338 "$=" => Some(Self::EndsWith),
339 "*=" => Some(Self::Contains),
340 ">" => Some(Self::GreaterThan),
341 "<" => Some(Self::LessThan),
342 ">=" => Some(Self::GreaterOrEqual),
343 "<=" => Some(Self::LessOrEqual),
344 _ => None,
345 }
346 }
347
348 pub fn to_filter_op(&self) -> FilterOp {
350 match self {
351 Self::Equal => FilterOp::Equals,
352 Self::NotEqual => FilterOp::NotEquals,
353 Self::Wildcard => FilterOp::WordMatch, Self::StartsWith => FilterOp::StartsWith,
355 Self::EndsWith => FilterOp::EndsWith,
356 Self::Contains => FilterOp::Contains,
357 Self::GreaterThan => FilterOp::GreaterThan,
358 Self::LessThan => FilterOp::LessThan,
359 Self::GreaterOrEqual => FilterOp::GreaterOrEqual,
360 Self::LessOrEqual => FilterOp::LessOrEqual,
361 }
362 }
363
364 pub fn from_filter_op(op: FilterOp) -> Self {
366 match op {
367 FilterOp::Exists => Self::Equal, FilterOp::Equals => Self::Equal,
369 FilterOp::NotEquals => Self::NotEqual,
370 FilterOp::WordMatch => Self::Wildcard,
371 FilterOp::StartsWith => Self::StartsWith,
372 FilterOp::EndsWith => Self::EndsWith,
373 FilterOp::Contains => Self::Contains,
374 FilterOp::GreaterThan => Self::GreaterThan,
375 FilterOp::LessThan => Self::LessThan,
376 FilterOp::GreaterOrEqual => Self::GreaterOrEqual,
377 FilterOp::LessOrEqual => Self::LessOrEqual,
378 }
379 }
380}
381
382#[derive(Debug, Clone)]
384pub enum FilterValue {
385 String(String),
387 Number(f64),
389 Bool(bool),
391 Pattern(Pattern),
393}
394
395#[derive(Debug, Clone)]
397pub enum PseudoSelector {
398 Root,
401 Empty,
403 FirstChild,
405 LastChild,
407 NthChild(usize),
409 OnlyChild,
411
412 Connected,
415 Unconnected,
417 Input,
419 Output,
421 Bidirectional,
423 Power,
425 Passive,
427 OpenCollector,
429 OpenEmitter,
431 HiZ,
433
434 Visible,
437 Hidden,
439 Selected,
441
442 Not(Box<Selector>),
445 Has(Box<Selector>),
447 Is(Box<Selector>),
449}
450
451impl PseudoSelector {
452 pub fn from_name(name: &str) -> Option<Self> {
454 match name.to_lowercase().as_str() {
455 "root" => Some(Self::Root),
456 "empty" => Some(Self::Empty),
457 "first-child" | "firstchild" => Some(Self::FirstChild),
458 "last-child" | "lastchild" => Some(Self::LastChild),
459 "only-child" | "onlychild" => Some(Self::OnlyChild),
460 "connected" => Some(Self::Connected),
461 "unconnected" => Some(Self::Unconnected),
462 "input" => Some(Self::Input),
463 "output" => Some(Self::Output),
464 "bidirectional" | "bidir" => Some(Self::Bidirectional),
465 "power" => Some(Self::Power),
466 "passive" => Some(Self::Passive),
467 "open-collector" | "opencollector" | "oc" => Some(Self::OpenCollector),
468 "open-emitter" | "openemitter" | "oe" => Some(Self::OpenEmitter),
469 "hiz" | "hi-z" | "high-z" => Some(Self::HiZ),
470 "visible" => Some(Self::Visible),
471 "hidden" => Some(Self::Hidden),
472 "selected" => Some(Self::Selected),
473 _ => None,
474 }
475 }
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
480pub enum Combinator {
481 Descendant,
483 DirectChild,
485}