Skip to content

Commit d9c5ae8

Browse files
committed
fix(graph): make graph format explicit
1 parent b99c4b1 commit d9c5ae8

File tree

5 files changed

+78
-16
lines changed

5 files changed

+78
-16
lines changed

crates/ros-z-protocol/src/format/ros2dds.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ impl KeyExprFormatter for Ros2DdsFormatter {
131131

132132
// Topic key expression (escaped)
133133
let topic_escaped = iter.next().ok_or(MissingTopicName)?;
134-
let topic = Self::demangle_name(topic_escaped);
134+
let topic = match Self::demangle_name(topic_escaped) {
135+
topic if topic.is_empty() => "/".to_string(),
136+
topic if topic.starts_with('/') => topic,
137+
topic => format!("/{}", topic),
138+
};
135139

136140
// Type name (escaped)
137141
let type_escaped = iter.next().ok_or(MissingTopicType)?;

crates/ros-z/src/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl ZContextBuilder {
9595
self
9696
}
9797

98-
/// Set the key expression format for ROS 2 entity mapping.
98+
/// Set the key expression format for ROS 2 entity mapping and graph discovery.
9999
///
100100
/// # Example
101101
/// ```ignore
@@ -533,7 +533,7 @@ impl Builder for ZContextBuilder {
533533
}
534534

535535
let domain_id = builder.domain_id;
536-
let graph = Arc::new(Graph::new(&session, domain_id)?);
536+
let graph = Arc::new(Graph::new(&session, domain_id, builder.keyexpr_format)?);
537537

538538
Ok(ZContext {
539539
session: Arc::new(session),

crates/ros-z/src/dynamic/tests/pubsub_tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ fn test_zpub_builder_with_dyn_schema() {
164164

165165
// Create a mock builder to test with_dyn_schema
166166
let session = zenoh::Wait::wait(zenoh::open(zenoh::Config::default())).unwrap();
167-
let graph = std::sync::Arc::new(crate::graph::Graph::new(&session, 0).unwrap());
167+
let graph = std::sync::Arc::new(
168+
crate::graph::Graph::new(&session, 0, ros_z_protocol::KeyExprFormat::default()).unwrap(),
169+
);
168170
let builder: ZPubBuilder<DynamicMessage> = ZPubBuilder {
169171
entity: crate::entity::EndpointEntity {
170172
id: 0,
@@ -204,7 +206,9 @@ fn test_zpub_builder_with_serdes_preserves_schema() {
204206

205207
// Create builder with schema
206208
let session = zenoh::Wait::wait(zenoh::open(zenoh::Config::default())).unwrap();
207-
let graph = std::sync::Arc::new(crate::graph::Graph::new(&session, 0).unwrap());
209+
let graph = std::sync::Arc::new(
210+
crate::graph::Graph::new(&session, 0, ros_z_protocol::KeyExprFormat::default()).unwrap(),
211+
);
208212
let builder: ZPubBuilder<DynamicMessage> = ZPubBuilder {
209213
entity: crate::entity::EndpointEntity {
210214
id: 0,

crates/ros-z/src/graph.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,33 @@ impl std::fmt::Debug for Graph {
431431
}
432432

433433
impl Graph {
434+
/// Create a new Graph using an explicit key expression format.
435+
///
436+
/// The format determines both the liveliness subscription pattern and the
437+
/// parser used to turn liveliness keys back into ROS entities.
438+
pub fn new(
439+
session: &Session,
440+
domain_id: usize,
441+
format: ros_z_protocol::KeyExprFormat,
442+
) -> Result<Self> {
443+
let liveliness_pattern = match format {
444+
ros_z_protocol::KeyExprFormat::RmwZenoh => {
445+
format!("{ADMIN_SPACE}/{domain_id}/**")
446+
}
447+
ros_z_protocol::KeyExprFormat::Ros2Dds => "@/*/@ros2_lv/**".to_string(),
448+
_ => {
449+
return Err(zenoh::Error::from(format!(
450+
"unsupported key expression format for graph construction: {:?}",
451+
format
452+
)));
453+
}
454+
};
455+
456+
Self::new_with_pattern(session, domain_id, liveliness_pattern, move |ke| {
457+
format.parse_liveliness(ke)
458+
})
459+
}
460+
434461
async fn wait_until<F>(&self, timeout: Duration, predicate: F) -> bool
435462
where
436463
F: Fn(&Self) -> bool,
@@ -458,17 +485,6 @@ impl Graph {
458485
}
459486
}
460487

461-
pub fn new(session: &Session, domain_id: usize) -> Result<Self> {
462-
// Default to RmwZenoh format
463-
let format = ros_z_protocol::KeyExprFormat::default();
464-
Self::new_with_pattern(
465-
session,
466-
domain_id,
467-
format!("{ADMIN_SPACE}/{domain_id}/**"),
468-
move |ke| format.parse_liveliness(ke),
469-
)
470-
}
471-
472488
/// Create a new Graph with a custom liveliness subscription pattern and parser
473489
///
474490
/// # Arguments

crates/ros-z/tests/graph.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,44 @@ mod tests {
677677
Ok(())
678678
}
679679

680+
/// Tests that a Ros2Dds context uses a Ros2Dds graph for introspection and matching.
681+
#[cfg(feature = "ros2dds")]
682+
#[tokio::test(flavor = "multi_thread")]
683+
async fn test_ros2dds_context_graph_tracks_local_entities() -> Result<()> {
684+
let ctx = ZContextBuilder::default()
685+
.keyexpr_format(ros_z_protocol::KeyExprFormat::Ros2Dds)
686+
.build()?;
687+
let pub_node = ctx.create_node("test_graph_pub_dds").build()?;
688+
let sub_node = ctx.create_node("test_graph_sub_dds").build()?;
689+
let topic_name = "/test_ros2dds_context_graph";
690+
691+
let publisher = pub_node.create_pub::<RosString>(topic_name).build()?;
692+
let subscriber = sub_node.create_sub::<RosString>(topic_name).build()?;
693+
694+
assert!(
695+
publisher
696+
.wait_for_subscription(1, Duration::from_secs(2))
697+
.await
698+
);
699+
assert!(
700+
subscriber
701+
.wait_for_publisher(1, Duration::from_secs(2))
702+
.await
703+
);
704+
705+
let graph = ctx.graph();
706+
assert!(
707+
graph.count(EntityKind::Publisher, topic_name) >= 1,
708+
"Expected Ros2Dds graph to discover local publisher"
709+
);
710+
assert!(
711+
graph.count(EntityKind::Subscription, topic_name) >= 1,
712+
"Expected Ros2Dds graph to discover local subscriber"
713+
);
714+
715+
Ok(())
716+
}
717+
680718
/// Tests getting action names and types from the graph
681719
#[tokio::test(flavor = "multi_thread")]
682720
async fn test_action_names_and_types() -> Result<()> {

0 commit comments

Comments
 (0)