@@ -403,6 +403,22 @@ impl NodeState {
403403 PublisherState :: < T > :: create ( options, Arc :: clone ( & self . handle ) )
404404 }
405405
406+ /// Creates a [`DynamicPublisher`], a publisher whose type is only known at runtime.
407+ ///
408+ /// Refer to [`Node::create_publisher`] for the API, the only key difference is that the
409+ /// publisher's message type is passed as a [`crate::MessageTypeName`] parameter.
410+ ///
411+ /// Pass in only the topic name for the `options` argument to use all default publisher options:
412+ /// ```
413+ /// # use rclrs::*;
414+ /// # let executor = Context::default().create_basic_executor();
415+ /// # let node = executor.create_node("my_node").unwrap();
416+ /// let publisher = node.create_dynamic_publisher(
417+ /// "test_msgs/msg/Empty".try_into().unwrap(),
418+ /// "my_topic"
419+ /// .keep_last(100)
420+ /// )
421+ /// .unwrap();
406422 #[ cfg( feature = "dyn_msg" ) ]
407423 pub fn create_dynamic_publisher < ' a > (
408424 & self ,
@@ -803,6 +819,42 @@ impl NodeState {
803819 )
804820 }
805821
822+ /// Creates a [`DynamicSubscription`] with an ordinary callback.
823+ ///
824+ /// For the behavior and API refer to [`Node::create_subscription`], except two key
825+ /// differences:
826+ ///
827+ /// - The message type is determined at runtime through the `topic_type` function parameter.
828+ /// - Only one type of callback is supported (returning both [`crate::DynamicMessage`] and
829+ /// [`crate::MessageInfo`]).
830+ ///
831+ /// # Message type passing
832+ ///
833+ /// The message type can be passed as a [`crate::MessageTypeName`] struct. The struct also implements `TryFrom<&str>`
834+ /// ```
835+ /// # use rclrs::*;
836+ /// # let executor = Context::default().create_basic_executor();
837+ /// # let node = executor.create_node("my_node").unwrap();
838+ /// let subscription = node.create_dynamic_subscription(
839+ /// MessageTypeName {
840+ /// package_name: "test_msgs".to_owned(),
841+ /// type_name: "Empty".to_owned(),
842+ /// },
843+ /// "my_topic"
844+ /// .transient_local(),
845+ /// |_msg: DynamicMessage, _info: MessageInfo| {
846+ /// println!("Received message!");
847+ /// },
848+ /// );
849+ ///
850+ /// let subscription = node.create_dynamic_subscription(
851+ /// "test_msgs/msg/Empty".try_into().unwrap(),
852+ /// "my_topic",
853+ /// |_msg: DynamicMessage, _info: MessageInfo| {
854+ /// println!("Received message!");
855+ /// },
856+ /// );
857+ /// ```
806858 #[ cfg( feature = "dyn_msg" ) ]
807859 pub fn create_dynamic_subscription < ' a , F > (
808860 & self ,
@@ -822,6 +874,60 @@ impl NodeState {
822874 )
823875 }
824876
877+ /// Creates a [`DynamicSubscription`] with an async callback.
878+ ///
879+ /// For the behavior and API refer to [`Node::create_async_subscription`], except two key
880+ /// differences:
881+ ///
882+ /// - The message type is determined at runtime through the `topic_type` function parameter.
883+ /// - Only one type of callback is supported (returning both [`crate::DynamicMessage`] and
884+ /// [`crate::MessageInfo`].
885+ ///
886+ /// # Message type passing
887+ ///
888+ /// The message type can be passed as a [`crate::MessageTypeName`] struct. The struct also implements `TryFrom<&str>`
889+ /// ```
890+ /// # use rclrs::*;
891+ /// # let executor = Context::default().create_basic_executor();
892+ /// # let node = executor.create_node("my_node").unwrap();
893+ /// use std::sync::Arc;
894+ ///
895+ /// let count_worker = node.create_worker(0_usize);
896+ /// let data_worker = node.create_worker(String::new());
897+ ///
898+ /// let service = node.create_async_dynamic_subscription(
899+ /// "example_interfaces/msg/String".try_into()?,
900+ /// "topic",
901+ /// move |msg: DynamicMessage, _info: MessageInfo| {
902+ /// // Clone the workers so they can be captured into the async block
903+ /// let count_worker = Arc::clone(&count_worker);
904+ /// let data_worker = Arc::clone(&data_worker);
905+ /// Box::pin(async move {
906+ /// // Update the message count
907+ /// let current_count = count_worker.run(move |count: &mut usize| {
908+ /// *count += 1;
909+ /// *count
910+ /// }).await.unwrap();
911+ ///
912+ /// // Change the data in the data_worker and get back the data
913+ /// // that was previously put in there.
914+ /// let previous = data_worker.run(move |data: &mut String| {
915+ /// let value = msg.get("data").unwrap();
916+ /// let Value::Simple(value) = value else {
917+ /// panic!("Unexpected value type, expected Simple value");
918+ /// };
919+ /// let SimpleValue::String(value) = value else {
920+ /// panic!("Unexpected value type, expected String");
921+ /// };
922+ /// std::mem::replace(data, value.to_string())
923+ /// }).await.unwrap();
924+ ///
925+ /// println!("Current count is {current_count}, data was previously {previous}");
926+ /// })
927+ /// }
928+ /// )?;
929+ /// # Ok::<(), RclrsError>(())
930+ /// ```
825931 #[ cfg( feature = "dyn_msg" ) ]
826932 pub fn create_async_dynamic_subscription < ' a , F > (
827933 & self ,
0 commit comments