1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Context of ROS2.
//! A context can create `Node` and `Selector`.
//!
//! # Example
//!
//! ```
//! use safe_drive::context::Context;
//!
//! // Create a context.
//! let ctx = Context::new().unwrap();
//!
//! // Create a node.
//! let node = ctx
//! .create_node("context_rs", None, Default::default())
//! .unwrap();
//!
//! // Create a selector.
//! let selector = ctx.create_selector().unwrap();
//! ```
use crate::{
error::*,
get_allocator,
node::{Node, NodeOptions},
rcl,
selector::{async_selector::SELECTOR, Selector},
signal_handler,
};
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use std::{env, ffi::CString, sync::Arc};
static CONTEXT: Lazy<Mutex<Option<Arc<Context>>>> = Lazy::new(|| Mutex::new(None));
/// Context of ROS2.
pub struct Context {
context: rcl::rcl_context_t,
}
impl Context {
/// Create a new context.
///
/// # Example
///
/// ```
/// use safe_drive::context::Context;
///
/// // Create a context.
/// let ctx = Context::new().unwrap();
/// ```
pub fn new() -> Result<Arc<Self>, DynError> {
signal_handler::init();
{
let guard = CONTEXT.lock();
if let Some(ctx) = guard.as_ref() {
return Ok(ctx.clone());
}
}
// allocate context
let mut context = rcl::MTSafeFn::rcl_get_zero_initialized_context();
// convert Args to Vec<*const c_ptr>
let cstr_args: Vec<_> = env::args().map(|s| CString::new(s).unwrap()).collect();
let args: Vec<_> = cstr_args.iter().map(|s| s.as_ptr()).collect();
let options = InitOptions::new()?;
{
let guard = rcl::MT_UNSAFE_FN.lock();
// initialize context
guard.rcl_init(
args.len() as i32,
args.as_ptr(),
options.as_ptr(),
&mut context,
)?;
}
let context = Arc::new(Context { context });
{
let mut guard = CONTEXT.lock();
*guard = Some(context.clone());
}
Ok(context)
}
/// Create a new node of ROS2.
///
/// # Example
///
/// ```
/// use safe_drive::context::Context;
///
/// // Create a context.
/// let ctx = Context::new().unwrap();
///
/// // Create a node.
/// let node = ctx
/// .create_node("context_rs", None, Default::default())
/// .unwrap();
/// ```
///
/// # Errors
///
/// - `RCLError::AlreadyInit` if the node has already be initialized, or
/// - `RCLError::NotInit` if the given context is invalid, or
/// - `RCLError::InvalidArgument` if any arguments are invalid, or
/// - `RCLError::BadAlloc` if allocating memory failed, or
/// - `RCLError::NodeInvalidName` if the name is invalid, or
/// - `RCLError::NodeInvalidNamespace` if the namespace_ is invalid, or
/// - `RCLError::Error` if an unspecified error occurs.
pub fn create_node(
self: &Arc<Self>,
name: &str,
namespace: Option<&str>,
options: NodeOptions,
) -> RCLResult<Arc<Node>> {
Node::new(self.clone(), name, namespace, options)
}
/// Create a new selector.
/// The selector is used to wait event and invoke callback for single threaded execution.
///
/// # Example
///
/// ```
/// use safe_drive::context::Context;
///
/// // Create a context.
/// let ctx = Context::new().unwrap();
///
/// // Create a selector.
/// let selector = ctx.create_selector().unwrap();
/// ```
///
/// # Errors
///
/// - `RCLError::AlreadyInit` if the wait set is not zero initialized, or
/// - `RCLError::NotInit` if the given context is invalid, or
/// - `RCLError::InvalidArgument` if any arguments are invalid, or
/// - `RCLError::BadAlloc` if allocating memory failed, or
/// - `RCLError::WaitSetInvalid` if the wait set is not destroyed properly, or
/// - `RCLError::Error` if an unspecified error occurs.
pub fn create_selector(self: &Arc<Self>) -> RCLResult<Selector> {
Selector::new(self.clone())
}
pub(crate) fn as_ptr(&self) -> *const rcl::rcl_context_t {
&self.context as *const _
}
pub(crate) unsafe fn as_ptr_mut(&self) -> *mut rcl::rcl_context_t {
&self.context as *const _ as *mut _
}
}
impl Drop for Context {
fn drop(&mut self) {
rcl::MTSafeFn::rcl_shutdown(&mut self.context).unwrap();
{
let guard = rcl::MT_UNSAFE_FN.lock();
guard.rcl_context_fini(&mut self.context).unwrap();
}
}
}
/// Options for the initialization of the context.
pub(crate) struct InitOptions {
options: rcl::rcl_init_options_t,
}
impl InitOptions {
/// Create options to initialize a context.
pub fn new() -> RCLResult<InitOptions> {
// allocate options
let mut options = rcl::MTSafeFn::rcl_get_zero_initialized_init_options();
// initialize options
{
let guard = rcl::MT_UNSAFE_FN.lock();
guard.rcl_init_options_init(&mut options, get_allocator())?;
}
Ok(InitOptions { options })
}
pub fn as_ptr(&self) -> *const rcl::rcl_init_options_t {
&self.options
}
pub fn as_ptr_mut(&mut self) -> *mut rcl::rcl_init_options_t {
&mut self.options
}
}
impl Drop for InitOptions {
fn drop(&mut self) {
let guard = rcl::MT_UNSAFE_FN.lock();
guard.rcl_init_options_fini(self.as_ptr_mut()).unwrap();
}
}
unsafe impl Sync for Context {}
unsafe impl Send for Context {}
#[no_mangle]
pub(crate) extern "C" fn remove_context() {
{
SELECTOR.lock().halt().unwrap();
}
signal_handler::halt();
{
let mut guard = CONTEXT.lock();
let _ = guard.take();
}
}