1use crate::output::NodeIdString;
14use clap::ValueEnum;
15use iceoryx2::node::NodeState;
16use iceoryx2::node::NodeView;
17use iceoryx2::service::ipc::Service;
18use iceoryx2::service::static_config::messaging_pattern::MessagingPattern;
19use iceoryx2::service::ServiceDetails;
20use iceoryx2_pal_posix::posix::pid_t;
21use std::fmt::Debug;
22use std::str::FromStr;
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 #[default]
119 All,
120}
121
122impl Filter<ServiceDetails<Service>> for MessagingPatternFilter {
123 fn matches(&self, service: &ServiceDetails<Service>) -> bool {
124 matches!(
125 (self, &service.static_details.messaging_pattern()),
126 (
127 MessagingPatternFilter::PublishSubscribe,
128 MessagingPattern::PublishSubscribe(_)
129 ) | (MessagingPatternFilter::Event, MessagingPattern::Event(_))
130 | (MessagingPatternFilter::All, _)
131 )
132 }
133}