isaac_sim_bridge/source.rs
1// SPDX-License-Identifier: MPL-2.0
2/// Filter for the per-source routing key adapters use to demultiplex
3/// dispatches from multiple sensors of the same type.
4///
5/// Centralised so all adapters share one definition of "matches" — if
6/// glob/regex/prefix matching ever lands, it lands in one place.
7///
8/// # Example
9///
10/// ```
11/// use isaac_sim_bridge::SourceFilter;
12/// let f = SourceFilter::exact("/World/Carter/lidar_2d");
13/// assert!(f.matches("/World/Carter/lidar_2d"));
14/// assert!(!f.matches("/World/Carter/lidar_3d"));
15/// ```
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct SourceFilter(String);
18
19impl SourceFilter {
20 /// Construct a filter that matches exactly `source` (no wildcards).
21 ///
22 /// # Example
23 ///
24 /// ```
25 /// use isaac_sim_bridge::SourceFilter;
26 /// let f = SourceFilter::exact("/World/lidar");
27 /// assert!(f.matches("/World/lidar"));
28 /// ```
29 pub fn exact(source: impl Into<String>) -> Self {
30 Self(source.into())
31 }
32
33 /// Returns `true` if `src` matches this filter exactly.
34 ///
35 /// # Example
36 ///
37 /// ```
38 /// use isaac_sim_bridge::SourceFilter;
39 /// let f = SourceFilter::exact("/sensor/a");
40 /// assert!(f.matches("/sensor/a"));
41 /// assert!(!f.matches("/sensor/b"));
42 /// ```
43 pub fn matches(&self, src: &str) -> bool {
44 self.0 == src
45 }
46
47 /// The raw filter string, e.g. a prim path like `/World/Carter/lidar_2d`.
48 pub fn as_str(&self) -> &str {
49 &self.0
50 }
51}
52
53impl From<String> for SourceFilter {
54 fn from(s: String) -> Self {
55 Self::exact(s)
56 }
57}
58
59impl From<&str> for SourceFilter {
60 fn from(s: &str) -> Self {
61 Self::exact(s)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn matches_exact_path() {
71 let f = SourceFilter::exact("/Root/World/Carter/lidar_2d");
72 assert!(f.matches("/Root/World/Carter/lidar_2d"));
73 assert!(!f.matches("/Root/World/Carter/lidar_3d"));
74 assert!(!f.matches(""));
75 }
76
77 #[test]
78 fn empty_filter_does_not_match_unset_source() {
79 let f = SourceFilter::exact("");
80 assert!(f.matches(""));
81 assert!(!f.matches("/anything"));
82 }
83}