use super::common::FilterOp;
use super::pattern::Pattern;
#[derive(Debug, Clone)]
pub struct Selector {
pub alternatives: Vec<SelectorChain>,
}
impl Selector {
pub fn single(chain: SelectorChain) -> Self {
Self {
alternatives: vec![chain],
}
}
pub fn any() -> Self {
Self::single(SelectorChain::single(SelectorSegment::any()))
}
pub fn is_empty(&self) -> bool {
self.alternatives.is_empty() || self.alternatives.iter().all(|c| c.segments.is_empty())
}
}
#[derive(Debug, Clone)]
pub struct SelectorChain {
pub segments: Vec<SelectorSegment>,
}
impl SelectorChain {
pub fn single(segment: SelectorSegment) -> Self {
Self {
segments: vec![segment],
}
}
pub fn empty() -> Self {
Self { segments: vec![] }
}
pub fn push(&mut self, segment: SelectorSegment) {
self.segments.push(segment);
}
}
#[derive(Debug, Clone)]
pub struct SelectorSegment {
pub matcher: RecordMatcher,
pub filters: Vec<PropertyFilter>,
pub pseudo: Vec<PseudoSelector>,
pub combinator: Option<Combinator>,
}
impl SelectorSegment {
pub fn any() -> Self {
Self {
matcher: RecordMatcher::Any,
filters: vec![],
pseudo: vec![],
combinator: None,
}
}
pub fn from_matcher(matcher: RecordMatcher) -> Self {
Self {
matcher,
filters: vec![],
pseudo: vec![],
combinator: None,
}
}
pub fn with_filter(mut self, filter: PropertyFilter) -> Self {
self.filters.push(filter);
self
}
pub fn with_pseudo(mut self, pseudo: PseudoSelector) -> Self {
self.pseudo.push(pseudo);
self
}
pub fn with_combinator(mut self, combinator: Combinator) -> Self {
self.combinator = Some(combinator);
self
}
}
#[derive(Debug, Clone)]
pub enum RecordMatcher {
Any,
Type(RecordType),
Designator(Pattern),
PartNumber(Pattern),
Net(Pattern),
Value(Pattern),
Sheet(Pattern),
Pin {
component: Pattern,
pin: Pattern,
},
NetConnected {
net: Pattern,
target: NetConnectedTarget,
},
DesignatorWithValue {
designator: Pattern,
value: Pattern,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NetConnectedTarget {
Pins,
Components,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RecordType {
Component,
Pin,
Wire,
NetLabel,
Port,
PowerObject,
Junction,
Label,
Rectangle,
Line,
Arc,
Ellipse,
Polygon,
Polyline,
Bezier,
Image,
Parameter,
Sheet,
Symbol,
Designator,
TextFrame,
}
impl RecordType {
pub fn try_parse(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"component" => Some(Self::Component),
"pin" => Some(Self::Pin),
"wire" => Some(Self::Wire),
"netlabel" | "net_label" => Some(Self::NetLabel),
"port" => Some(Self::Port),
"power" | "powerobject" | "power_object" => Some(Self::PowerObject),
"junction" => Some(Self::Junction),
"label" => Some(Self::Label),
"rectangle" | "rect" => Some(Self::Rectangle),
"line" => Some(Self::Line),
"arc" => Some(Self::Arc),
"ellipse" => Some(Self::Ellipse),
"polygon" => Some(Self::Polygon),
"polyline" => Some(Self::Polyline),
"bezier" => Some(Self::Bezier),
"image" => Some(Self::Image),
"parameter" | "param" => Some(Self::Parameter),
"sheet" => Some(Self::Sheet),
"symbol" => Some(Self::Symbol),
"designator" => Some(Self::Designator),
"textframe" | "text_frame" => Some(Self::TextFrame),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Component => "component",
Self::Pin => "pin",
Self::Wire => "wire",
Self::NetLabel => "netlabel",
Self::Port => "port",
Self::PowerObject => "power",
Self::Junction => "junction",
Self::Label => "label",
Self::Rectangle => "rectangle",
Self::Line => "line",
Self::Arc => "arc",
Self::Ellipse => "ellipse",
Self::Polygon => "polygon",
Self::Polyline => "polyline",
Self::Bezier => "bezier",
Self::Image => "image",
Self::Parameter => "parameter",
Self::Sheet => "sheet",
Self::Symbol => "symbol",
Self::Designator => "designator",
Self::TextFrame => "textframe",
}
}
}
#[derive(Debug, Clone)]
pub struct PropertyFilter {
pub property: String,
pub operator: FilterOperator,
pub value: FilterValue,
}
impl PropertyFilter {
pub fn new(property: impl Into<String>, operator: FilterOperator, value: FilterValue) -> Self {
Self {
property: property.into(),
operator,
value,
}
}
pub fn eq(property: impl Into<String>, value: impl Into<String>) -> Self {
Self::new(
property,
FilterOperator::Equal,
FilterValue::String(value.into()),
)
}
pub fn matches(property: impl Into<String>, pattern: Pattern) -> Self {
Self::new(
property,
FilterOperator::Wildcard,
FilterValue::Pattern(pattern),
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilterOperator {
Equal,
NotEqual,
Wildcard,
StartsWith,
EndsWith,
Contains,
GreaterThan,
LessThan,
GreaterOrEqual,
LessOrEqual,
}
impl FilterOperator {
pub fn try_parse(s: &str) -> Option<Self> {
match s {
"=" => Some(Self::Equal),
"!=" => Some(Self::NotEqual),
"~=" => Some(Self::Wildcard),
"^=" => Some(Self::StartsWith),
"$=" => Some(Self::EndsWith),
"*=" => Some(Self::Contains),
">" => Some(Self::GreaterThan),
"<" => Some(Self::LessThan),
">=" => Some(Self::GreaterOrEqual),
"<=" => Some(Self::LessOrEqual),
_ => None,
}
}
pub fn to_filter_op(&self) -> FilterOp {
match self {
Self::Equal => FilterOp::Equals,
Self::NotEqual => FilterOp::NotEquals,
Self::Wildcard => FilterOp::WordMatch, Self::StartsWith => FilterOp::StartsWith,
Self::EndsWith => FilterOp::EndsWith,
Self::Contains => FilterOp::Contains,
Self::GreaterThan => FilterOp::GreaterThan,
Self::LessThan => FilterOp::LessThan,
Self::GreaterOrEqual => FilterOp::GreaterOrEqual,
Self::LessOrEqual => FilterOp::LessOrEqual,
}
}
pub fn from_filter_op(op: FilterOp) -> Self {
match op {
FilterOp::Exists => Self::Equal, FilterOp::Equals => Self::Equal,
FilterOp::NotEquals => Self::NotEqual,
FilterOp::WordMatch => Self::Wildcard,
FilterOp::StartsWith => Self::StartsWith,
FilterOp::EndsWith => Self::EndsWith,
FilterOp::Contains => Self::Contains,
FilterOp::GreaterThan => Self::GreaterThan,
FilterOp::LessThan => Self::LessThan,
FilterOp::GreaterOrEqual => Self::GreaterOrEqual,
FilterOp::LessOrEqual => Self::LessOrEqual,
}
}
}
#[derive(Debug, Clone)]
pub enum FilterValue {
String(String),
Number(f64),
Bool(bool),
Pattern(Pattern),
}
#[derive(Debug, Clone)]
pub enum PseudoSelector {
Root,
Empty,
FirstChild,
LastChild,
NthChild(usize),
OnlyChild,
Connected,
Unconnected,
Input,
Output,
Bidirectional,
Power,
Passive,
OpenCollector,
OpenEmitter,
HiZ,
Visible,
Hidden,
Selected,
Not(Box<Selector>),
Has(Box<Selector>),
Is(Box<Selector>),
}
impl PseudoSelector {
pub fn from_name(name: &str) -> Option<Self> {
match name.to_lowercase().as_str() {
"root" => Some(Self::Root),
"empty" => Some(Self::Empty),
"first-child" | "firstchild" => Some(Self::FirstChild),
"last-child" | "lastchild" => Some(Self::LastChild),
"only-child" | "onlychild" => Some(Self::OnlyChild),
"connected" => Some(Self::Connected),
"unconnected" => Some(Self::Unconnected),
"input" => Some(Self::Input),
"output" => Some(Self::Output),
"bidirectional" | "bidir" => Some(Self::Bidirectional),
"power" => Some(Self::Power),
"passive" => Some(Self::Passive),
"open-collector" | "opencollector" | "oc" => Some(Self::OpenCollector),
"open-emitter" | "openemitter" | "oe" => Some(Self::OpenEmitter),
"hiz" | "hi-z" | "high-z" => Some(Self::HiZ),
"visible" => Some(Self::Visible),
"hidden" => Some(Self::Hidden),
"selected" => Some(Self::Selected),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Combinator {
Descendant,
DirectChild,
}