@@ -55,10 +55,10 @@ pub(crate) struct ContextHandle {
55
55
impl Context {
56
56
/// Creates a new context.
57
57
///
58
- /// Usually, this would be called with `std::env::args()`, analogously to `rclcpp::init()`.
58
+ /// Usually this would be called with `std::env::args()`, analogously to `rclcpp::init()`.
59
59
/// See also the official "Passing ROS arguments to nodes via the command-line" tutorial.
60
60
///
61
- /// Creating a context can fail in case the args contain invalid ROS arguments.
61
+ /// Creating a context will fail if the args contain invalid ROS arguments.
62
62
///
63
63
/// # Example
64
64
/// ```
@@ -68,6 +68,21 @@ impl Context {
68
68
/// assert!(Context::new(invalid_remapping).is_err());
69
69
/// ```
70
70
pub fn new ( args : impl IntoIterator < Item = String > ) -> Result < Self , RclrsError > {
71
+ Self :: new_with_options ( args, InitOptions :: new ( ) )
72
+ }
73
+
74
+ /// Same as [`Context::new`] except you can additionally provide initialization options.
75
+ ///
76
+ /// # Example
77
+ /// ```
78
+ /// use rclrs::{Context, InitOptions};
79
+ /// let context = Context::new_with_options([], InitOptions::new().with_domain_id(Some(5))).unwrap();
80
+ /// assert_eq!(context.domain_id(), 5);
81
+ /// ````
82
+ pub fn new_with_options (
83
+ args : impl IntoIterator < Item =String > ,
84
+ options : InitOptions ,
85
+ ) -> Result < Self , RclrsError > {
71
86
// SAFETY: Getting a zero-initialized value is always safe
72
87
let mut rcl_context = unsafe { rcl_get_zero_initialized_context ( ) } ;
73
88
let cstring_args: Vec < CString > = args
@@ -84,11 +99,7 @@ impl Context {
84
99
unsafe {
85
100
// SAFETY: No preconditions for this function.
86
101
let allocator = rcutils_get_default_allocator ( ) ;
87
- // SAFETY: Getting a zero-initialized value is always safe.
88
- let mut rcl_init_options = rcl_get_zero_initialized_init_options ( ) ;
89
- // SAFETY: Passing in a zero-initialized value is expected.
90
- // In the case where this returns not ok, there's nothing to clean up.
91
- rcl_init_options_init ( & mut rcl_init_options, allocator) . ok ( ) ?;
102
+ let mut rcl_init_options = options. into_rcl ( allocator) ?;
92
103
// SAFETY: This function does not store the ephemeral init_options and c_args
93
104
// pointers. Passing in a zero-initialized rcl_context is expected.
94
105
let ret = rcl_init (
@@ -115,6 +126,25 @@ impl Context {
115
126
} )
116
127
}
117
128
129
+ /// Returns the ROS domain ID that the context is using.
130
+ ///
131
+ /// The domain ID controls which nodes can send messages to each other, see the [ROS 2 concept article][1].
132
+ /// It can be set through the `ROS_DOMAIN_ID` environment variable.
133
+ ///
134
+ /// [1]: https://docs.ros.org/en/rolling/Concepts/About-Domain-ID.html
135
+ pub fn domain_id ( & self ) -> u8 {
136
+ let mut domain_id: usize = 0 ;
137
+ let ret = unsafe {
138
+ rcl_context_get_domain_id (
139
+ & mut * self . handle . rcl_context . lock ( ) . unwrap ( ) ,
140
+ & mut domain_id
141
+ )
142
+ } ;
143
+
144
+ debug_assert_eq ! ( ret, 0 ) ;
145
+ domain_id as u8
146
+ }
147
+
118
148
/// Checks if the context is still valid.
119
149
///
120
150
/// This will return `false` when a signal has caused the context to shut down (currently
@@ -128,6 +158,59 @@ impl Context {
128
158
}
129
159
}
130
160
161
+ /// Additional options for initializing the Context.
162
+ #[ derive( Default , Clone ) ]
163
+ pub struct InitOptions {
164
+ /// The domain ID that should be used by the Context. Set to None to ask for
165
+ /// the default behavior, which is to set the domain ID according to the
166
+ /// [ROS_DOMAIN_ID][1] environment variable.
167
+ ///
168
+ /// [1]: https://docs.ros.org/en/rolling/Concepts/Intermediate/About-Domain-ID.html#the-ros-domain-id
169
+ domain_id : Option < u8 > ,
170
+ }
171
+
172
+ impl InitOptions {
173
+ /// Create a new InitOptions with all default values.
174
+ pub fn new ( ) -> InitOptions {
175
+ Self :: default ( )
176
+ }
177
+
178
+ /// Transform an InitOptions into a new one with a certain domain_id
179
+ pub fn with_domain_id ( mut self , domain_id : Option < u8 > ) -> InitOptions {
180
+ self . domain_id = domain_id;
181
+ self
182
+ }
183
+
184
+ /// Set the domain_id of an InitOptions, or reset it to the default behavior
185
+ /// (determined by environment variables) by providing None.
186
+ pub fn set_domain_id ( & mut self , domain_id : Option < u8 > ) {
187
+ self . domain_id = domain_id;
188
+ }
189
+
190
+ /// Get the domain_id that will be provided by these InitOptions.
191
+ pub fn domain_id ( & self ) -> Option < u8 > {
192
+ self . domain_id
193
+ }
194
+
195
+ fn into_rcl ( self , allocator : rcutils_allocator_s ) -> Result < rcl_init_options_t , RclrsError > {
196
+ unsafe {
197
+ // SAFETY: Getting a zero-initialized value is always safe.
198
+ let mut rcl_init_options = rcl_get_zero_initialized_init_options ( ) ;
199
+ // SAFETY: Passing in a zero-initialized value is expected.
200
+ // In the case where this returns not ok, there's nothing to clean up.
201
+ rcl_init_options_init ( & mut rcl_init_options, allocator) . ok ( ) ?;
202
+
203
+ // We only need to set the domain_id if the user asked for something
204
+ // other than None. When the user asks for None, that is equivalent
205
+ // to the default value in rcl_init_options.
206
+ if let Some ( domain_id) = self . domain_id {
207
+ rcl_init_options_set_domain_id ( & mut rcl_init_options, domain_id as usize ) ;
208
+ }
209
+ return Ok ( rcl_init_options) ;
210
+ }
211
+ }
212
+ }
213
+
131
214
#[ cfg( test) ]
132
215
mod tests {
133
216
use super :: * ;
0 commit comments