Skip to content

Commit bf3d01a

Browse files
committed
Migrate Node to shared state pattern
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 066dd7c commit bf3d01a

File tree

15 files changed

+70
-57
lines changed

15 files changed

+70
-57
lines changed

examples/minimal_pub_sub/src/minimal_two_nodes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use anyhow::{Error, Result};
1010

1111
struct MinimalSubscriber {
1212
num_messages: AtomicU32,
13-
node: Arc<rclrs::Node>,
13+
node: rclrs::Node,
1414
subscription: Mutex<Option<Arc<rclrs::Subscription<std_msgs::msg::String>>>>,
1515
}
1616

examples/rust_pubsub/src/simple_publisher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rclrs::{create_node, Context, Node, Publisher, RclrsError, QOS_PROFILE_DEFAU
22
use std::{sync::Arc, thread, time::Duration};
33
use std_msgs::msg::String as StringMsg;
44
struct SimplePublisherNode {
5-
node: Arc<Node>,
5+
node: Node,
66
_publisher: Arc<Publisher<StringMsg>>,
77
}
88
impl SimplePublisherNode {

examples/rust_pubsub/src/simple_subscriber.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{
77
};
88
use std_msgs::msg::String as StringMsg;
99
pub struct SimpleSubscriptionNode {
10-
node: Arc<Node>,
10+
node: Node,
1111
_subscriber: Arc<Subscription<StringMsg>>,
1212
data: Arc<Mutex<Option<StringMsg>>>,
1313
}

rclrs/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ type RequestId = i64;
6767
/// The only available way to instantiate clients is via [`Node::create_client`][1], this is to
6868
/// ensure that [`Node`][2]s can track all the clients that have been created.
6969
///
70-
/// [1]: crate::Node::create_client
70+
/// [1]: crate::NodeState::create_client
7171
/// [2]: crate::Node
7272
pub struct Client<T>
7373
where

rclrs/src/executor.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
use crate::{rcl_bindings::rcl_context_is_valid, Node, RclReturnCode, RclrsError, WaitSet};
1+
use crate::{
2+
rcl_bindings::rcl_context_is_valid, Node, NodeState, RclReturnCode, RclrsError, WaitSet,
3+
};
24
use std::{
35
sync::{Arc, Mutex, Weak},
46
time::Duration,
57
};
68

79
/// Single-threaded executor implementation.
810
pub struct SingleThreadedExecutor {
9-
nodes_mtx: Mutex<Vec<Weak<Node>>>,
11+
nodes_mtx: Mutex<Vec<Weak<NodeState>>>,
1012
}
1113

1214
impl Default for SingleThreadedExecutor {
@@ -24,13 +26,13 @@ impl SingleThreadedExecutor {
2426
}
2527

2628
/// Add a node to the executor.
27-
pub fn add_node(&self, node: &Arc<Node>) -> Result<(), RclrsError> {
29+
pub fn add_node(&self, node: &Node) -> Result<(), RclrsError> {
2830
{ self.nodes_mtx.lock().unwrap() }.push(Arc::downgrade(node));
2931
Ok(())
3032
}
3133

3234
/// Remove a node from the executor.
33-
pub fn remove_node(&self, node: Arc<Node>) -> Result<(), RclrsError> {
35+
pub fn remove_node(&self, node: Node) -> Result<(), RclrsError> {
3436
{ self.nodes_mtx.lock().unwrap() }
3537
.retain(|n| !n.upgrade().map(|n| Arc::ptr_eq(&n, &node)).unwrap_or(false));
3638
Ok(())

rclrs/src/lib.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod rcl_bindings;
3030
#[cfg(feature = "dyn_msg")]
3131
pub mod dynamic_message;
3232

33-
use std::{sync::Arc, time::Duration};
33+
use std::time::Duration;
3434

3535
pub use arguments::*;
3636
pub use client::*;
@@ -59,14 +59,14 @@ pub use wait::*;
5959
/// This can usually be ignored.
6060
///
6161
/// [1]: crate::RclReturnCode
62-
pub fn spin_once(node: Arc<Node>, timeout: Option<Duration>) -> Result<(), RclrsError> {
62+
pub fn spin_once(node: Node, timeout: Option<Duration>) -> Result<(), RclrsError> {
6363
let executor = SingleThreadedExecutor::new();
6464
executor.add_node(&node)?;
6565
executor.spin_once(timeout)
6666
}
6767

6868
/// Convenience function for calling [`spin_once`] in a loop.
69-
pub fn spin(node: Arc<Node>) -> Result<(), RclrsError> {
69+
pub fn spin(node: Node) -> Result<(), RclrsError> {
7070
let executor = SingleThreadedExecutor::new();
7171
executor.add_node(&node)?;
7272
executor.spin()
@@ -77,7 +77,7 @@ pub fn spin(node: Arc<Node>) -> Result<(), RclrsError> {
7777
/// Convenience function equivalent to [`Node::new`][1].
7878
/// Please see that function's documentation.
7979
///
80-
/// [1]: crate::Node::new
80+
/// [1]: crate::NodeState::new
8181
///
8282
/// # Example
8383
/// ```
@@ -87,17 +87,17 @@ pub fn spin(node: Arc<Node>) -> Result<(), RclrsError> {
8787
/// assert!(node.is_ok());
8888
/// # Ok::<(), RclrsError>(())
8989
/// ```
90-
pub fn create_node(context: &Context, node_name: &str) -> Result<Arc<Node>, RclrsError> {
91-
Node::new(context, node_name)
90+
pub fn create_node(context: &Context, node_name: &str) -> Result<Node, RclrsError> {
91+
NodeState::new(context, node_name)
9292
}
9393

9494
/// Creates a [`NodeBuilder`].
9595
///
96-
/// Convenience function equivalent to [`NodeBuilder::new()`][1] and [`Node::builder()`][2].
96+
/// Convenience function equivalent to [`NodeBuilder::new()`][1] and [`NodeState::builder()`][2].
9797
/// Please see that function's documentation.
9898
///
9999
/// [1]: crate::NodeBuilder::new
100-
/// [2]: crate::Node::builder
100+
/// [2]: crate::NodeState::builder
101101
///
102102
/// # Example
103103
/// ```
@@ -109,5 +109,5 @@ pub fn create_node(context: &Context, node_name: &str) -> Result<Arc<Node>, Rclr
109109
/// # Ok::<(), RclrsError>(())
110110
/// ```
111111
pub fn create_node_builder(context: &Context, node_name: &str) -> NodeBuilder {
112-
Node::builder(context, node_name)
112+
NodeState::builder(context, node_name)
113113
}

rclrs/src/node.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ unsafe impl Send for rcl_node_t {}
4848
/// In that sense, the parameters to the node creation functions are only the _default_ namespace and
4949
/// name.
5050
/// See also the [official tutorial][1] on the command line arguments for ROS nodes, and the
51-
/// [`Node::namespace()`] and [`Node::name()`] functions for examples.
51+
/// [`NodeState::namespace()`] and [`NodeState::name()`] functions for examples.
5252
///
5353
/// ## Rules for valid names
5454
/// The rules for valid node names and node namespaces are explained in
@@ -58,7 +58,18 @@ unsafe impl Send for rcl_node_t {}
5858
/// [2]: https://docs.ros.org/en/rolling/How-To-Guides/Node-arguments.html
5959
/// [3]: crate::NodeBuilder::new
6060
/// [4]: crate::NodeBuilder::namespace
61-
pub struct Node {
61+
pub type Node = Arc<NodeState>;
62+
63+
/// The inner state of a [`Node`].
64+
///
65+
/// This is public so that you can choose to put it inside a [`Weak`] if you
66+
/// want to be able to refer to a [`Node`] in a non-owning way. It is generally
67+
/// recommended to manage the [`NodeState`] inside of an [`Arc`], and [`Node`]
68+
/// recommended to manage the `NodeState` inside of an [`Arc`], and [`Node`]
69+
/// is provided as convenience alias for that.
70+
///
71+
/// The public API of the [`Node`] type is implemented via `NodeState`.
72+
pub struct NodeState {
6273
pub(crate) clients_mtx: Mutex<Vec<Weak<dyn ClientBase>>>,
6374
pub(crate) guard_conditions_mtx: Mutex<Vec<Weak<GuardCondition>>>,
6475
pub(crate) services_mtx: Mutex<Vec<Weak<dyn ServiceBase>>>,
@@ -89,28 +100,28 @@ impl Drop for NodeHandle {
89100
}
90101
}
91102

92-
impl Eq for Node {}
103+
impl Eq for NodeState {}
93104

94-
impl PartialEq for Node {
105+
impl PartialEq for NodeState {
95106
fn eq(&self, other: &Self) -> bool {
96107
Arc::ptr_eq(&self.handle, &other.handle)
97108
}
98109
}
99110

100-
impl fmt::Debug for Node {
111+
impl fmt::Debug for NodeState {
101112
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
102113
f.debug_struct("Node")
103114
.field("fully_qualified_name", &self.fully_qualified_name())
104115
.finish()
105116
}
106117
}
107118

108-
impl Node {
119+
impl NodeState {
109120
/// Creates a new node in the empty namespace.
110121
///
111122
/// See [`NodeBuilder::new()`] for documentation.
112123
#[allow(clippy::new_ret_no_self)]
113-
pub fn new(context: &Context, node_name: &str) -> Result<Arc<Node>, RclrsError> {
124+
pub fn new(context: &Context, node_name: &str) -> Result<Node, RclrsError> {
114125
Self::builder(context, node_name).build()
115126
}
116127

@@ -171,7 +182,7 @@ impl Node {
171182
/// Returns the fully qualified name of the node.
172183
///
173184
/// The fully qualified name of the node is the node namespace combined with the node name.
174-
/// It is subject to the remappings shown in [`Node::name()`] and [`Node::namespace()`].
185+
/// It is subject to the remappings shown in [`NodeState::name()`] and [`NodeState::namespace()`].
175186
///
176187
/// # Example
177188
/// ```
@@ -431,9 +442,9 @@ impl Node {
431442
///
432443
/// # Example
433444
/// ```
434-
/// # use rclrs::{Context, Node, RclrsError};
445+
/// # use rclrs::{Context, NodeState, RclrsError};
435446
/// let context = Context::new([])?;
436-
/// let node = Node::builder(&context, "my_node").build()?;
447+
/// let node = NodeState::builder(&context, "my_node").build()?;
437448
/// assert_eq!(node.name(), "my_node");
438449
/// # Ok::<(), RclrsError>(())
439450
/// ```

rclrs/src/node/builder.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ use std::{
44
};
55

66
use crate::{
7-
rcl_bindings::*, ClockType, Context, ContextHandle, Node, NodeHandle, ParameterInterface,
8-
QoSProfile, RclrsError, TimeSource, ToResult, ENTITY_LIFECYCLE_MUTEX, QOS_PROFILE_CLOCK,
7+
rcl_bindings::*, ClockType, Context, ContextHandle, Node, NodeHandle, NodeState,
8+
ParameterInterface, QoSProfile, RclrsError, TimeSource, ToResult, ENTITY_LIFECYCLE_MUTEX,
9+
QOS_PROFILE_CLOCK,
910
};
1011

1112
/// A builder for creating a [`Node`][1].
1213
///
1314
/// The builder pattern allows selectively setting some fields, and leaving all others at their default values.
14-
/// This struct instance can be created via [`Node::builder()`][2].
15+
/// This struct instance can be created via [`NodeState::builder()`][2].
1516
///
1617
/// The default values for optional fields are:
1718
/// - `namespace: "/"`
@@ -24,25 +25,25 @@ use crate::{
2425
///
2526
/// # Example
2627
/// ```
27-
/// # use rclrs::{Context, NodeBuilder, Node, RclrsError};
28+
/// # use rclrs::{Context, NodeBuilder, NodeState, RclrsError};
2829
/// let context = Context::new([])?;
2930
/// // Building a node in a single expression
3031
/// let node = NodeBuilder::new(&context, "foo_node").namespace("/bar").build()?;
3132
/// assert_eq!(node.name(), "foo_node");
3233
/// assert_eq!(node.namespace(), "/bar");
33-
/// // Building a node via Node::builder()
34-
/// let node = Node::builder(&context, "bar_node").build()?;
34+
/// // Building a node via NodeState::builder()
35+
/// let node = NodeState::builder(&context, "bar_node").build()?;
3536
/// assert_eq!(node.name(), "bar_node");
3637
/// // Building a node step-by-step
37-
/// let mut builder = Node::builder(&context, "goose");
38+
/// let mut builder = NodeState::builder(&context, "goose");
3839
/// builder = builder.namespace("/duck/duck");
3940
/// let node = builder.build()?;
4041
/// assert_eq!(node.fully_qualified_name(), "/duck/duck/goose");
4142
/// # Ok::<(), RclrsError>(())
4243
/// ```
4344
///
4445
/// [1]: crate::Node
45-
/// [2]: crate::Node::builder
46+
/// [2]: crate::NodeState::builder
4647
pub struct NodeBuilder {
4748
context: Arc<ContextHandle>,
4849
name: String,
@@ -126,22 +127,22 @@ impl NodeBuilder {
126127
///
127128
/// # Example
128129
/// ```
129-
/// # use rclrs::{Context, Node, RclrsError, RclReturnCode};
130+
/// # use rclrs::{Context, NodeState, RclrsError, RclReturnCode};
130131
/// let context = Context::new([])?;
131132
/// // This is a valid namespace
132-
/// let builder_ok_ns = Node::builder(&context, "my_node").namespace("/some/nested/namespace");
133+
/// let builder_ok_ns = NodeState::builder(&context, "my_node").namespace("/some/nested/namespace");
133134
/// assert!(builder_ok_ns.build().is_ok());
134135
/// // This is an invalid namespace
135136
/// assert!(matches!(
136-
/// Node::builder(&context, "my_node")
137+
/// NodeState::builder(&context, "my_node")
137138
/// .namespace("/10_percent_luck/20_percent_skill")
138139
/// .build()
139140
/// .unwrap_err(),
140141
/// RclrsError::RclError { code: RclReturnCode::NodeInvalidNamespace, .. }
141142
/// ));
142143
/// // A missing forward slash at the beginning is automatically added
143144
/// assert_eq!(
144-
/// Node::builder(&context, "my_node")
145+
/// NodeState::builder(&context, "my_node")
145146
/// .namespace("foo")
146147
/// .build()?
147148
/// .namespace(),
@@ -262,7 +263,7 @@ impl NodeBuilder {
262263
/// For example usage, see the [`NodeBuilder`][1] docs.
263264
///
264265
/// [1]: crate::NodeBuilder
265-
pub fn build(&self) -> Result<Arc<Node>, RclrsError> {
266+
pub fn build(&self) -> Result<Node, RclrsError> {
266267
let node_name =
267268
CString::new(self.name.as_str()).map_err(|err| RclrsError::StringContainsNul {
268269
err,
@@ -308,7 +309,7 @@ impl NodeBuilder {
308309
&rcl_context.global_arguments,
309310
)?
310311
};
311-
let node = Arc::new(Node {
312+
let node = Arc::new(NodeState {
312313
handle,
313314
clients_mtx: Mutex::new(vec![]),
314315
guard_conditions_mtx: Mutex::new(vec![]),

rclrs/src/node/graph.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{
33
ffi::{CStr, CString},
44
};
55

6-
use crate::{rcl_bindings::*, Node, RclrsError, ToResult};
6+
use crate::{rcl_bindings::*, NodeState, RclrsError, ToResult};
77

88
impl Drop for rmw_names_and_types_t {
99
fn drop(&mut self) {
@@ -57,7 +57,7 @@ pub struct TopicEndpointInfo {
5757
pub topic_type: String,
5858
}
5959

60-
impl Node {
60+
impl NodeState {
6161
/// Returns a list of topic names and types for publishers associated with a node.
6262
pub fn get_publisher_names_and_types_by_node(
6363
&self,
@@ -486,7 +486,7 @@ mod tests {
486486
Context::new_with_options([], InitOptions::new().with_domain_id(Some(domain_id)))
487487
.unwrap();
488488
let node_name = "test_publisher_names_and_types";
489-
let node = Node::new(&context, node_name).unwrap();
489+
let node = NodeState::new(&context, node_name).unwrap();
490490
// Test that the graph has no publishers
491491
let names_and_topics = node
492492
.get_publisher_names_and_types_by_node(node_name, "")
@@ -545,7 +545,7 @@ mod tests {
545545
fn test_node_names() {
546546
let context = Context::new([]).unwrap();
547547
let node_name = "test_node_names";
548-
let node = Node::new(&context, node_name).unwrap();
548+
let node = NodeState::new(&context, node_name).unwrap();
549549

550550
let names_and_namespaces = node.get_node_names().unwrap();
551551

@@ -561,7 +561,7 @@ mod tests {
561561
fn test_node_names_with_enclaves() {
562562
let context = Context::new([]).unwrap();
563563
let node_name = "test_node_names_with_enclaves";
564-
let node = Node::new(&context, node_name).unwrap();
564+
let node = NodeState::new(&context, node_name).unwrap();
565565

566566
let names_and_namespaces = node.get_node_names_with_enclaves().unwrap();
567567

rclrs/src/parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ enum DeclaredValue {
8282
}
8383

8484
/// Builder used to declare a parameter. Obtain this by calling
85-
/// [`crate::Node::declare_parameter`].
85+
/// [`crate::NodeState::declare_parameter`].
8686
#[must_use]
8787
pub struct ParameterBuilder<'a, T: ParameterVariant> {
8888
name: Arc<str>,

0 commit comments

Comments
 (0)