iceoryx2_cli/
filter.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13use 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}