1use crate::output::NodeIdString;
14use clap::ValueEnum;
15use core::fmt::Debug;
16use core::str::FromStr;
17use iceoryx2::node::NodeState;
18use iceoryx2::node::NodeView;
19use iceoryx2::service::ipc::Service;
20use iceoryx2::service::static_config::messaging_pattern::MessagingPattern;
21use iceoryx2::service::ServiceDetails;
22use iceoryx2_pal_posix::posix::pid_t;
23
24pub trait Filter<T>: Debug {
25 fn matches(&self, item: &T) -> bool;
26}
27
28#[derive(Clone, Debug)]
29pub enum NodeIdentifier {
30 Name(String),
31 Id(String),
32 Pid(pid_t),
33}
34
35impl NodeIdentifier {
36 fn is_valid_id(s: &str) -> bool {
37 s.len() == 32 && s.chars().all(|c| c.is_ascii_hexdigit())
38 }
39}
40
41impl FromStr for NodeIdentifier {
42 type Err = String;
43
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
45 if let Ok(pid) = s.parse::<pid_t>() {
46 Ok(NodeIdentifier::Pid(pid))
47 } else if Self::is_valid_id(s) {
48 Ok(NodeIdentifier::Id(s.to_string()))
49 } else {
50 Ok(NodeIdentifier::Name(s.to_string()))
51 }
52 }
53}
54
55#[derive(Debug, Clone, ValueEnum)]
56#[clap(rename_all = "PascalCase")]
57#[derive(Default)]
58pub enum StateFilter {
59 Alive,
60 Dead,
61 Inaccessible,
62 Undefined,
63 #[default]
64 All,
65}
66
67impl Filter<NodeState<Service>> for NodeIdentifier {
68 fn matches(&self, node: &NodeState<Service>) -> bool {
69 match self {
70 NodeIdentifier::Name(ref name) => match node {
71 NodeState::Alive(view) => view
72 .details()
73 .as_ref()
74 .map(|details| details.name().as_str() == name)
75 .unwrap_or(false),
76 NodeState::Dead(view) => view
77 .details()
78 .as_ref()
79 .map(|details| details.name().as_str() == name)
80 .unwrap_or(false),
81 NodeState::Inaccessible(_) | NodeState::Undefined(_) => false,
82 },
83 NodeIdentifier::Id(ref id) => match node {
84 NodeState::Alive(view) => NodeIdString::from(view.id()) == **id,
85 NodeState::Dead(view) => NodeIdString::from(view.id()) == **id,
86 NodeState::Inaccessible(node_id) => NodeIdString::from(node_id) == **id,
87 NodeState::Undefined(node_id) => NodeIdString::from(node_id) == **id,
88 },
89 NodeIdentifier::Pid(pid) => match node {
90 NodeState::Alive(view) => view.id().pid().value() == *pid,
91 NodeState::Dead(view) => view.id().pid().value() == *pid,
92 NodeState::Inaccessible(node_id) => node_id.pid().value() == *pid,
93 NodeState::Undefined(node_id) => node_id.pid().value() == *pid,
94 },
95 }
96 }
97}
98
99impl Filter<NodeState<Service>> for StateFilter {
100 fn matches(&self, node: &NodeState<Service>) -> bool {
101 matches!(
102 (self, node),
103 (StateFilter::Alive, NodeState::Alive(_))
104 | (StateFilter::Dead, NodeState::Dead(_))
105 | (StateFilter::Inaccessible, NodeState::Inaccessible(_))
106 | (StateFilter::Undefined, NodeState::Undefined(_))
107 | (StateFilter::All, _)
108 )
109 }
110}
111
112#[derive(Debug, Clone, ValueEnum)]
113#[clap(rename_all = "PascalCase")]
114#[derive(Default)]
115pub enum MessagingPatternFilter {
116 PublishSubscribe,
117 Event,
118 RequestResponse,
119 #[default]
120 All,
121}
122
123impl Filter<ServiceDetails<Service>> for MessagingPatternFilter {
124 fn matches(&self, service: &ServiceDetails<Service>) -> bool {
125 match self {
126 MessagingPatternFilter::All => true,
127 MessagingPatternFilter::PublishSubscribe => {
128 matches!(
129 service.static_details.messaging_pattern(),
130 MessagingPattern::PublishSubscribe(_)
131 )
132 }
133 MessagingPatternFilter::Event => {
134 matches!(
135 service.static_details.messaging_pattern(),
136 MessagingPattern::Event(_)
137 )
138 }
139 MessagingPatternFilter::RequestResponse => {
140 matches!(
141 service.static_details.messaging_pattern(),
142 MessagingPattern::RequestResponse(_)
143 )
144 }
145 }
146 }
147}