1use std::collections::HashSet;
4
5use super::QueryMatch;
6use super::ast::*;
7use super::schql_parser::QueryError;
8use super::view::*;
9
10pub struct QueryExecutor<'a> {
12 view: &'a SchematicView,
13}
14
15impl<'a> QueryExecutor<'a> {
16 pub fn new(view: &'a SchematicView) -> Self {
18 Self { view }
19 }
20
21 pub fn execute(&self, selector: &Selector) -> Result<Vec<QueryMatch>, QueryError> {
23 let matches = self.execute_selector(selector)?;
24
25 let matches = self.apply_result_modifiers(matches, selector);
27
28 Ok(matches)
29 }
30
31 fn execute_selector(&self, selector: &Selector) -> Result<Vec<QueryMatch>, QueryError> {
32 match selector {
33 Selector::Element(elem_type) => self.select_element(*elem_type),
34 Selector::Id(id) => self.select_id(id),
35 Selector::Universal => self.select_all(),
36 Selector::Attribute(attr) => self.filter_by_attribute(&self.select_all()?, attr),
37 Selector::Pseudo(pseudo) => self.filter_by_pseudo(&self.select_all()?, pseudo),
38 Selector::Compound(parts) => self.select_compound(parts),
39 Selector::Combinator {
40 left,
41 combinator,
42 right,
43 } => self.select_combinator(left, *combinator, right),
44 Selector::Union(selectors) => self.select_union(selectors),
45 Selector::Not(inner) => self.select_not(inner),
46 Selector::Has(inner) => self.select_has(inner),
47 }
48 }
49
50 fn select_element(&self, elem_type: ElementType) -> Result<Vec<QueryMatch>, QueryError> {
51 match elem_type {
52 ElementType::Component => Ok(self
53 .view
54 .components
55 .iter()
56 .map(|c| self.component_to_match(c))
57 .collect()),
58 ElementType::Pin => Ok(self.all_pins()),
59 ElementType::Net => Ok(self
60 .view
61 .nets
62 .iter()
63 .map(|n| self.net_to_match(n))
64 .collect()),
65 ElementType::Port => Ok(self
66 .view
67 .ports
68 .iter()
69 .map(|p| self.port_to_match(p))
70 .collect()),
71 ElementType::Wire => Ok(self
72 .view
73 .wires
74 .iter()
75 .enumerate()
76 .map(|(i, w)| self.wire_to_match(i, w))
77 .collect()),
78 ElementType::Power => Ok(self
79 .view
80 .power_symbols
81 .iter()
82 .filter(|p| !p.is_ground)
83 .map(|p| self.power_to_match(p))
84 .collect()),
85 ElementType::Ground => Ok(self
86 .view
87 .power_symbols
88 .iter()
89 .filter(|p| p.is_ground)
90 .map(|p| self.power_to_match(p))
91 .collect()),
92 ElementType::Label => Ok(self
93 .view
94 .labels
95 .iter()
96 .map(|l| self.label_to_match(l))
97 .collect()),
98 ElementType::Junction => Ok(self
99 .view
100 .junctions
101 .iter()
102 .map(|j| self.junction_to_match(j))
103 .collect()),
104 ElementType::Parameter => Ok(self.all_parameters()),
105 ElementType::Designator => Ok(self
106 .view
107 .components
108 .iter()
109 .map(|c| QueryMatch::Parameter {
110 component_designator: c.designator.clone(),
111 name: "Designator".to_string(),
112 value: c.designator.clone(),
113 })
114 .collect()),
115 ElementType::Sheet => {
116 Ok(vec![QueryMatch::Component {
118 designator: "Sheet".to_string(),
119 part: self.view.sheet_name.clone().unwrap_or_default(),
120 description: format!(
121 "{} components, {} nets",
122 self.view.components.len(),
123 self.view.nets.len()
124 ),
125 value: None,
126 footprint: None,
127 pin_count: 0,
128 }])
129 }
130 }
131 }
132
133 fn select_id(&self, id: &str) -> Result<Vec<QueryMatch>, QueryError> {
134 let id_upper = id.to_uppercase();
135
136 if let Some(comp) = self.view.get_component(id) {
138 return Ok(vec![self.component_to_match(comp)]);
139 }
140 for comp in &self.view.components {
142 if comp.designator.to_uppercase() == id_upper {
143 return Ok(vec![self.component_to_match(comp)]);
144 }
145 }
146
147 if let Some(net) = self.view.get_net(id) {
149 return Ok(vec![self.net_to_match(net)]);
150 }
151 for net in &self.view.nets {
153 if net.name.to_uppercase() == id_upper {
154 return Ok(vec![self.net_to_match(net)]);
155 }
156 }
157
158 for port in &self.view.ports {
160 if port.name.to_uppercase() == id_upper {
161 return Ok(vec![self.port_to_match(port)]);
162 }
163 }
164
165 for pwr in &self.view.power_symbols {
167 if pwr.net_name.to_uppercase() == id_upper {
168 return Ok(vec![self.power_to_match(pwr)]);
169 }
170 }
171
172 Ok(vec![])
173 }
174
175 fn select_all(&self) -> Result<Vec<QueryMatch>, QueryError> {
176 let mut matches = Vec::new();
177 matches.extend(
178 self.view
179 .components
180 .iter()
181 .map(|c| self.component_to_match(c)),
182 );
183 matches.extend(self.all_pins());
184 matches.extend(self.view.nets.iter().map(|n| self.net_to_match(n)));
185 matches.extend(self.view.ports.iter().map(|p| self.port_to_match(p)));
186 matches.extend(
187 self.view
188 .power_symbols
189 .iter()
190 .map(|p| self.power_to_match(p)),
191 );
192 Ok(matches)
193 }
194
195 fn select_compound(&self, parts: &[Selector]) -> Result<Vec<QueryMatch>, QueryError> {
196 if parts.is_empty() {
197 return Ok(vec![]);
198 }
199
200 let mut matches = self.execute_selector(&parts[0])?;
202
203 for part in &parts[1..] {
205 matches = self.filter_matches(matches, part)?;
206 }
207
208 Ok(matches)
209 }
210
211 fn filter_matches(
212 &self,
213 matches: Vec<QueryMatch>,
214 selector: &Selector,
215 ) -> Result<Vec<QueryMatch>, QueryError> {
216 match selector {
217 Selector::Attribute(attr) => self.filter_by_attribute(&matches, attr),
218 Selector::Pseudo(pseudo) => self.filter_by_pseudo(&matches, pseudo),
219 Selector::Element(elem_type) => Ok(matches
220 .into_iter()
221 .filter(|m| self.match_has_type(m, *elem_type))
222 .collect()),
223 Selector::Id(id) => {
224 let id_upper = id.to_uppercase();
225 Ok(matches
226 .into_iter()
227 .filter(|m| match m {
228 QueryMatch::Component { designator, .. } => {
229 designator.to_uppercase() == id_upper
230 }
231 QueryMatch::Net { name, .. } => name.to_uppercase() == id_upper,
232 QueryMatch::Port { name, .. } => name.to_uppercase() == id_upper,
233 QueryMatch::Power { net_name, .. } => net_name.to_uppercase() == id_upper,
234 _ => false,
235 })
236 .collect())
237 }
238 Selector::Not(inner) => {
239 let excluded = self.execute_selector(inner)?;
240 let excluded_set: HashSet<String> = excluded
241 .iter()
242 .map(|m: &QueryMatch| m.to_short_text())
243 .collect();
244 Ok(matches
245 .into_iter()
246 .filter(|m: &QueryMatch| !excluded_set.contains(&m.to_short_text()))
247 .collect())
248 }
249 _ => Ok(matches),
250 }
251 }
252
253 fn select_combinator(
254 &self,
255 left: &Selector,
256 combinator: CombinatorType,
257 right: &Selector,
258 ) -> Result<Vec<QueryMatch>, QueryError> {
259 match combinator {
260 CombinatorType::Child | CombinatorType::Descendant => {
261 let parents = self.execute_selector(left)?;
263 let mut results = Vec::new();
264
265 for parent in parents {
266 let children = self.get_children(&parent, right)?;
268 results.extend(children);
269 }
270
271 Ok(results)
272 }
273 CombinatorType::OnNet => {
274 let nets = self.execute_selector(left)?;
276 let mut results = Vec::new();
277
278 for net_match in nets {
279 if let QueryMatch::Net { ref name, .. } = net_match {
280 if let Some(net) = self.view.get_net(name) {
282 for conn in &net.connections {
283 if let ConnectionPoint::Pin {
284 component_designator,
285 pin_designator,
286 pin_name,
287 } = conn
288 {
289 let pin_match = QueryMatch::Pin {
291 component_designator: component_designator.clone(),
292 designator: pin_designator.clone(),
293 name: pin_name.clone(),
294 electrical_type: "".to_string(),
295 connected_net: Some(name.clone()),
296 is_hidden: false,
297 };
298 if self.match_satisfies_selector(&pin_match, right)? {
299 results.push(pin_match);
300 }
301 }
302 }
303 }
304 }
305 }
306
307 Ok(results)
308 }
309 CombinatorType::Connected => {
310 let sources = self.execute_selector(left)?;
312 let mut connected_nets: HashSet<String> = HashSet::new();
313
314 for source in &sources {
316 match source {
317 QueryMatch::Component { designator, .. } => {
318 if let Some(comp) = self.view.get_component(designator) {
319 for pin in &comp.pins {
320 if let Some(net) = &pin.connected_net {
321 connected_nets.insert(net.clone());
322 }
323 }
324 }
325 }
326 QueryMatch::Pin {
327 connected_net: Some(net),
328 ..
329 } => {
330 connected_nets.insert(net.clone());
331 }
332 QueryMatch::Net { name, .. } => {
333 connected_nets.insert(name.clone());
334 }
335 _ => {}
336 }
337 }
338
339 let mut results = Vec::new();
341 for net_name in connected_nets {
342 if let Some(net) = self.view.get_net(&net_name) {
343 for conn in &net.connections {
344 if let ConnectionPoint::Pin {
345 component_designator,
346 ..
347 } = conn
348 {
349 if let Some(comp) = self.view.get_component(component_designator) {
351 let comp_match = self.component_to_match(comp);
352 if self.match_satisfies_selector(&comp_match, right)? {
353 if !results.iter().any(|m| {
355 if let QueryMatch::Component { designator, .. } = m {
356 designator == component_designator
357 } else {
358 false
359 }
360 }) {
361 results.push(comp_match);
362 }
363 }
364 }
365 }
366 }
367 }
368 }
369
370 Ok(results)
371 }
372 CombinatorType::Sibling => {
373 let left_matches = self.execute_selector(left)?;
375 let mut results = Vec::new();
376
377 for left_match in left_matches {
378 if let QueryMatch::Pin {
379 component_designator,
380 ..
381 } = &left_match
382 {
383 if let Some(comp) = self.view.get_component(component_designator) {
385 for pin in &comp.pins {
386 let pin_match = self.pin_to_match(comp, pin);
387 if self.match_satisfies_selector(&pin_match, right)? {
388 results.push(pin_match);
389 }
390 }
391 }
392 }
393 }
394
395 Ok(results)
396 }
397 CombinatorType::Adjacent => {
398 self.select_combinator(left, CombinatorType::Descendant, right)
400 }
401 }
402 }
403
404 fn select_union(&self, selectors: &[Selector]) -> Result<Vec<QueryMatch>, QueryError> {
405 let mut all_matches: Vec<QueryMatch> = Vec::new();
406 let mut seen: HashSet<String> = HashSet::new();
407
408 for sel in selectors {
409 let matches: Vec<QueryMatch> = self.execute_selector(sel)?;
410 for m in matches {
411 let key = m.to_short_text();
412 if !seen.contains(&key) {
413 seen.insert(key);
414 all_matches.push(m);
415 }
416 }
417 }
418
419 Ok(all_matches)
420 }
421
422 fn select_not(&self, inner: &Selector) -> Result<Vec<QueryMatch>, QueryError> {
423 let all: Vec<QueryMatch> = self.select_all()?;
424 let excluded: Vec<QueryMatch> = self.execute_selector(inner)?;
425 let excluded_set: HashSet<String> = excluded
426 .iter()
427 .map(|m: &QueryMatch| m.to_short_text())
428 .collect();
429
430 Ok(all
431 .into_iter()
432 .filter(|m: &QueryMatch| !excluded_set.contains(&m.to_short_text()))
433 .collect())
434 }
435
436 fn select_has(&self, inner: &Selector) -> Result<Vec<QueryMatch>, QueryError> {
437 let mut results = Vec::new();
439
440 for comp in &self.view.components {
441 for pin in &comp.pins {
443 let pin_match = self.pin_to_match(comp, pin);
444 if self.match_satisfies_selector(&pin_match, inner)? {
445 results.push(self.component_to_match(comp));
446 break;
447 }
448 }
449 }
450
451 Ok(results)
452 }
453
454 fn get_children(
455 &self,
456 parent: &QueryMatch,
457 child_selector: &Selector,
458 ) -> Result<Vec<QueryMatch>, QueryError> {
459 match parent {
460 QueryMatch::Component { designator, .. } => {
461 if let Some(comp) = self.view.get_component(designator) {
462 let mut children = Vec::new();
463
464 for pin in &comp.pins {
466 let pin_match = self.pin_to_match(comp, pin);
467 if self.match_satisfies_selector(&pin_match, child_selector)? {
468 children.push(pin_match);
469 }
470 }
471
472 for (name, value) in &comp.parameters {
474 let param_match = QueryMatch::Parameter {
475 component_designator: designator.clone(),
476 name: name.clone(),
477 value: value.clone(),
478 };
479 if self.match_satisfies_selector(¶m_match, child_selector)? {
480 children.push(param_match);
481 }
482 }
483
484 Ok(children)
485 } else {
486 Ok(vec![])
487 }
488 }
489 _ => Ok(vec![]),
490 }
491 }
492
493 fn match_satisfies_selector(
494 &self,
495 m: &QueryMatch,
496 selector: &Selector,
497 ) -> Result<bool, QueryError> {
498 match selector {
499 Selector::Element(elem_type) => Ok(self.match_has_type(m, *elem_type)),
500 Selector::Id(id) => {
501 let id_upper = id.to_uppercase();
502 Ok(match m {
503 QueryMatch::Component { designator, .. } => {
504 designator.to_uppercase() == id_upper
505 }
506 QueryMatch::Pin {
507 component_designator,
508 designator,
509 ..
510 } => {
511 designator.to_uppercase() == id_upper
512 || format!("{}.{}", component_designator, designator).to_uppercase()
513 == id_upper
514 }
515 QueryMatch::Net { name, .. } => name.to_uppercase() == id_upper,
516 QueryMatch::Port { name, .. } => name.to_uppercase() == id_upper,
517 _ => false,
518 })
519 }
520 Selector::Universal => Ok(true),
521 Selector::Attribute(attr) => Ok(self.match_has_attribute(m, attr)),
522 Selector::Pseudo(pseudo) => Ok(self.match_has_pseudo(m, pseudo)),
523 Selector::Compound(parts) => {
524 for part in parts {
525 if !self.match_satisfies_selector(m, part)? {
526 return Ok(false);
527 }
528 }
529 Ok(true)
530 }
531 Selector::Not(inner) => Ok(!self.match_satisfies_selector(m, inner)?),
532 _ => Ok(true),
533 }
534 }
535
536 fn match_has_type(&self, m: &QueryMatch, elem_type: ElementType) -> bool {
537 matches!(
538 (m, elem_type),
539 (QueryMatch::Component { .. }, ElementType::Component)
540 | (QueryMatch::Pin { .. }, ElementType::Pin)
541 | (QueryMatch::Net { .. }, ElementType::Net)
542 | (QueryMatch::Port { .. }, ElementType::Port)
543 | (QueryMatch::Wire { .. }, ElementType::Wire)
544 | (
545 QueryMatch::Power {
546 is_ground: false,
547 ..
548 },
549 ElementType::Power
550 )
551 | (
552 QueryMatch::Power {
553 is_ground: true,
554 ..
555 },
556 ElementType::Ground
557 )
558 | (QueryMatch::Label { .. }, ElementType::Label)
559 | (QueryMatch::Junction { .. }, ElementType::Junction)
560 | (QueryMatch::Parameter { .. }, ElementType::Parameter)
561 )
562 }
563
564 fn filter_by_attribute(
565 &self,
566 matches: &[QueryMatch],
567 attr: &AttributeSelector,
568 ) -> Result<Vec<QueryMatch>, QueryError> {
569 Ok(matches
570 .iter()
571 .filter(|m| self.match_has_attribute(m, attr))
572 .cloned()
573 .collect())
574 }
575
576 fn match_has_attribute(&self, m: &QueryMatch, attr: &AttributeSelector) -> bool {
577 let value = self.get_attribute_value(m, &attr.name);
578 attr.matches(value)
579 }
580
581 fn get_attribute_value<'b>(&'b self, m: &'b QueryMatch, attr_name: &str) -> Option<&'b str> {
582 let attr_lower = attr_name.to_lowercase();
583
584 match m {
585 QueryMatch::Component {
586 designator,
587 part,
588 description,
589 value,
590 footprint,
591 ..
592 } => {
593 match attr_lower.as_str() {
594 "designator" | "des" | "ref" => Some(designator.as_str()),
595 "part" | "partname" | "libref" => Some(part.as_str()),
596 "description" | "desc" => Some(description.as_str()),
597 "value" | "val" => value.as_deref(),
598 "footprint" | "fp" | "package" => footprint.as_deref(),
599 "pins" | "pincount" => None, _ => None,
601 }
602 }
603 QueryMatch::Pin {
604 component_designator,
605 designator,
606 name,
607 electrical_type,
608 connected_net,
609 is_hidden,
610 ..
611 } => match attr_lower.as_str() {
612 "designator" | "des" | "num" | "number" | "pin" => Some(designator.as_str()),
613 "name" | "pinname" => Some(name.as_str()),
614 "type" | "electrical" | "elec" => Some(electrical_type.as_str()),
615 "net" | "netname" => connected_net.as_deref(),
616 "component" | "comp" => Some(component_designator.as_str()),
617 "hidden" => {
618 if *is_hidden {
619 Some("true")
620 } else {
621 Some("false")
622 }
623 }
624 _ => None,
625 },
626 QueryMatch::Net {
627 name,
628 is_power,
629 is_ground,
630 ..
631 } => match attr_lower.as_str() {
632 "name" | "netname" => Some(name.as_str()),
633 "power" => {
634 if *is_power {
635 Some("true")
636 } else {
637 Some("false")
638 }
639 }
640 "ground" | "gnd" => {
641 if *is_ground {
642 Some("true")
643 } else {
644 Some("false")
645 }
646 }
647 _ => None,
648 },
649 QueryMatch::Port {
650 name,
651 io_type,
652 connected_net,
653 ..
654 } => match attr_lower.as_str() {
655 "name" => Some(name.as_str()),
656 "io" | "iotype" | "type" | "direction" => Some(io_type.as_str()),
657 "net" | "netname" => connected_net.as_deref(),
658 _ => None,
659 },
660 QueryMatch::Power {
661 net_name,
662 style,
663 is_ground,
664 ..
665 } => match attr_lower.as_str() {
666 "name" | "netname" | "net" => Some(net_name.as_str()),
667 "style" => Some(style.as_str()),
668 "ground" | "gnd" => {
669 if *is_ground {
670 Some("true")
671 } else {
672 Some("false")
673 }
674 }
675 _ => None,
676 },
677 QueryMatch::Parameter {
678 component_designator,
679 name,
680 value,
681 } => match attr_lower.as_str() {
682 "name" => Some(name.as_str()),
683 "value" | "val" => Some(value.as_str()),
684 "component" | "comp" => Some(component_designator.as_str()),
685 _ => None,
686 },
687 QueryMatch::Label { text, .. } => match attr_lower.as_str() {
688 "text" | "name" | "net" => Some(text.as_str()),
689 _ => None,
690 },
691 _ => None,
692 }
693 }
694
695 fn filter_by_pseudo(
696 &self,
697 matches: &[QueryMatch],
698 pseudo: &PseudoSelector,
699 ) -> Result<Vec<QueryMatch>, QueryError> {
700 if pseudo.is_result_modifier() {
702 return Ok(matches.to_vec());
703 }
704
705 Ok(matches
706 .iter()
707 .filter(|m| self.match_has_pseudo(m, pseudo))
708 .cloned()
709 .collect())
710 }
711
712 fn match_has_pseudo(&self, m: &QueryMatch, pseudo: &PseudoSelector) -> bool {
713 match pseudo {
714 PseudoSelector::Connected => match m {
715 QueryMatch::Pin { connected_net, .. } => connected_net.is_some(),
716 QueryMatch::Net {
717 connection_count, ..
718 } => *connection_count > 0,
719 QueryMatch::Port { connected_net, .. } => connected_net.is_some(),
720 _ => true,
721 },
722 PseudoSelector::Unconnected => match m {
723 QueryMatch::Pin { connected_net, .. } => connected_net.is_none(),
724 QueryMatch::Net {
725 connection_count, ..
726 } => *connection_count == 0,
727 _ => false,
728 },
729 PseudoSelector::Power => match m {
730 QueryMatch::Net { is_power, .. } => *is_power,
731 QueryMatch::Pin {
732 electrical_type, ..
733 } => electrical_type == "Power",
734 QueryMatch::Power { is_ground, .. } => !*is_ground,
735 _ => false,
736 },
737 PseudoSelector::Ground => match m {
738 QueryMatch::Net { is_ground, .. } => *is_ground,
739 QueryMatch::Power { is_ground, .. } => *is_ground,
740 _ => false,
741 },
742 PseudoSelector::Input => match m {
743 QueryMatch::Pin {
744 electrical_type, ..
745 } => electrical_type == "Input",
746 QueryMatch::Port { io_type, .. } => io_type.to_uppercase().contains("INPUT"),
747 _ => false,
748 },
749 PseudoSelector::Output => match m {
750 QueryMatch::Pin {
751 electrical_type, ..
752 } => electrical_type == "Output",
753 QueryMatch::Port { io_type, .. } => io_type.to_uppercase().contains("OUTPUT"),
754 _ => false,
755 },
756 PseudoSelector::Bidirectional => match m {
757 QueryMatch::Pin {
758 electrical_type, ..
759 } => electrical_type == "Bidirectional",
760 QueryMatch::Port { io_type, .. } => io_type.to_uppercase().contains("BIDIR"),
761 _ => false,
762 },
763 PseudoSelector::Passive => match m {
764 QueryMatch::Pin {
765 electrical_type, ..
766 } => electrical_type == "Passive",
767 _ => false,
768 },
769 PseudoSelector::OpenCollector => match m {
770 QueryMatch::Pin {
771 electrical_type, ..
772 } => electrical_type == "OpenCollector",
773 _ => false,
774 },
775 PseudoSelector::OpenEmitter => match m {
776 QueryMatch::Pin {
777 electrical_type, ..
778 } => electrical_type == "OpenEmitter",
779 _ => false,
780 },
781 PseudoSelector::HiZ => match m {
782 QueryMatch::Pin {
783 electrical_type, ..
784 } => electrical_type == "HiZ",
785 _ => false,
786 },
787 PseudoSelector::Hidden => match m {
788 QueryMatch::Pin { is_hidden, .. } => *is_hidden,
789 _ => false,
790 },
791 PseudoSelector::Visible => match m {
792 QueryMatch::Pin { is_hidden, .. } => !*is_hidden,
793 _ => true,
794 },
795 _ => true,
797 }
798 }
799
800 fn apply_result_modifiers(
801 &self,
802 mut matches: Vec<QueryMatch>,
803 selector: &Selector,
804 ) -> Vec<QueryMatch> {
805 let modifiers = selector.get_result_modifiers();
806
807 for modifier in modifiers {
808 match modifier {
809 PseudoSelector::Count => {
810 return vec![QueryMatch::Count(matches.len())];
811 }
812 PseudoSelector::First => {
813 return matches.into_iter().take(1).collect();
814 }
815 PseudoSelector::Last => {
816 return matches.into_iter().last().into_iter().collect();
817 }
818 PseudoSelector::Nth(n) => {
819 if *n > 0 && *n <= matches.len() {
820 return vec![matches.remove(*n - 1)];
821 }
822 return vec![];
823 }
824 PseudoSelector::NthLast(n) => {
825 if *n > 0 && *n <= matches.len() {
826 let idx = matches.len() - *n;
827 return vec![matches.remove(idx)];
828 }
829 return vec![];
830 }
831 PseudoSelector::Even => {
832 return matches
833 .into_iter()
834 .enumerate()
835 .filter(|(i, _)| i % 2 == 1)
836 .map(|(_, m)| m)
837 .collect();
838 }
839 PseudoSelector::Odd => {
840 return matches
841 .into_iter()
842 .enumerate()
843 .filter(|(i, _)| i % 2 == 0)
844 .map(|(_, m)| m)
845 .collect();
846 }
847 PseudoSelector::Limit(n) => {
848 matches = matches.into_iter().take(*n).collect();
849 }
850 PseudoSelector::Offset(n) => {
851 matches = matches.into_iter().skip(*n).collect();
852 }
853 _ => {}
854 }
855 }
856
857 matches
858 }
859
860 fn component_to_match(&self, comp: &ComponentView) -> QueryMatch {
863 QueryMatch::Component {
864 designator: comp.designator.clone(),
865 part: comp.part_name.clone(),
866 description: comp.description.clone(),
867 value: comp.value.clone(),
868 footprint: comp.footprint.clone(),
869 pin_count: comp.pins.len(),
870 }
871 }
872
873 fn pin_to_match(&self, comp: &ComponentView, pin: &PinView) -> QueryMatch {
874 QueryMatch::Pin {
875 component_designator: comp.designator.clone(),
876 designator: pin.designator.clone(),
877 name: pin.name.clone(),
878 electrical_type: pin.electrical_type.as_str().to_string(),
879 connected_net: pin.connected_net.clone(),
880 is_hidden: pin.is_hidden,
881 }
882 }
883
884 fn all_pins(&self) -> Vec<QueryMatch> {
885 let mut pins = Vec::new();
886 for comp in &self.view.components {
887 for pin in &comp.pins {
888 pins.push(self.pin_to_match(comp, pin));
889 }
890 }
891 pins
892 }
893
894 fn net_to_match(&self, net: &NetView) -> QueryMatch {
895 QueryMatch::Net {
896 name: net.name.clone(),
897 is_power: net.is_power,
898 is_ground: net.is_ground,
899 connection_count: net.connections.len(),
900 connections: net
901 .connections
902 .iter()
903 .map(|c| c.to_short_string())
904 .collect(),
905 }
906 }
907
908 fn port_to_match(&self, port: &PortView) -> QueryMatch {
909 QueryMatch::Port {
910 name: port.name.clone(),
911 io_type: port.io_type.clone(),
912 connected_net: port.connected_net.clone(),
913 }
914 }
915
916 fn wire_to_match(&self, index: usize, wire: &WireView) -> QueryMatch {
917 let start = wire.vertices.first().copied().unwrap_or((0, 0));
918 let end = wire.vertices.last().copied().unwrap_or((0, 0));
919 QueryMatch::Wire {
920 index,
921 vertex_count: wire.vertices.len(),
922 start,
923 end,
924 }
925 }
926
927 fn power_to_match(&self, power: &PowerView) -> QueryMatch {
928 QueryMatch::Power {
929 net_name: power.net_name.clone(),
930 style: power.style.clone(),
931 is_ground: power.is_ground,
932 }
933 }
934
935 fn label_to_match(&self, label: &LabelView) -> QueryMatch {
936 QueryMatch::Label {
937 text: label.text.clone(),
938 location: label.location,
939 }
940 }
941
942 fn junction_to_match(&self, junction: &JunctionView) -> QueryMatch {
943 QueryMatch::Junction {
944 location: junction.location,
945 }
946 }
947
948 fn all_parameters(&self) -> Vec<QueryMatch> {
949 let mut params = Vec::new();
950 for comp in &self.view.components {
951 for (name, value) in &comp.parameters {
952 params.push(QueryMatch::Parameter {
953 component_designator: comp.designator.clone(),
954 name: name.clone(),
955 value: value.clone(),
956 });
957 }
958 }
959 params
960 }
961}
962
963#[cfg(test)]
964mod tests {
965 #[test]
968 fn test_executor_creation() {
969 }
971}