Skip to content

Commit 3f0360f

Browse files
committed
add context builder (ros2-rust#206)
1 parent 7adb4f6 commit 3f0360f

File tree

7 files changed

+53
-673
lines changed

7 files changed

+53
-673
lines changed

rclrs/src/builder.rs

Lines changed: 0 additions & 3 deletions
This file was deleted.

rclrs/src/clock.rs

Lines changed: 0 additions & 204 deletions
This file was deleted.

rclrs/src/context.rs

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
mod builder;
22

33
use crate::rcl_bindings::*;
4-
use crate::{RclrsError, ToResult};
4+
use crate::RclrsError;
55

66
use self::builder::*;
7-
use std::ffi::CString;
8-
use std::os::raw::c_char;
97
use std::string::String;
108
use std::sync::Arc;
11-
use std::vec::Vec;
129

1310
use parking_lot::Mutex;
1411

@@ -63,49 +60,8 @@ impl Context {
6360
/// assert!(Context::new(invalid_remapping).is_err());
6461
/// ```
6562
pub fn new(args: impl IntoIterator<Item = String>) -> Result<Self, RclrsError> {
66-
// SAFETY: Getting a zero-initialized value is always safe
67-
let mut rcl_context = unsafe { rcl_get_zero_initialized_context() };
68-
let cstring_args: Vec<CString> = args
69-
.into_iter()
70-
.map(|arg| {
71-
CString::new(arg.as_str()).map_err(|err| RclrsError::StringContainsNul {
72-
err,
73-
s: arg.clone(),
74-
})
75-
})
76-
.collect::<Result<_, _>>()?;
77-
// Vector of pointers into cstring_args
78-
let c_args: Vec<*const c_char> = cstring_args.iter().map(|arg| arg.as_ptr()).collect();
79-
unsafe {
80-
// SAFETY: No preconditions for this function.
81-
let allocator = rcutils_get_default_allocator();
82-
// SAFETY: Getting a zero-initialized value is always safe.
83-
let mut rcl_init_options = rcl_get_zero_initialized_init_options();
84-
// SAFETY: Passing in a zero-initialized value is expected.
85-
// In the case where this returns not ok, there's nothing to clean up.
86-
rcl_init_options_init(&mut rcl_init_options, allocator).ok()?;
87-
// SAFETY: This function does not store the ephemeral init_options and c_args
88-
// pointers. Passing in a zero-initialized rcl_context is expected.
89-
let ret = rcl_init(
90-
c_args.len() as i32,
91-
if c_args.is_empty() {
92-
std::ptr::null()
93-
} else {
94-
c_args.as_ptr()
95-
},
96-
&rcl_init_options,
97-
&mut rcl_context,
98-
)
99-
.ok();
100-
// SAFETY: It's safe to pass in an initialized object.
101-
// Early return will not leak memory, because this is the last fini function.
102-
rcl_init_options_fini(&mut rcl_init_options).ok()?;
103-
// Move the check after the last fini()
104-
ret?;
105-
}
106-
Ok(Self {
107-
rcl_context_mtx: Arc::new(Mutex::new(rcl_context)),
108-
})
63+
let builder = ContextBuilder::new(args)?;
64+
builder.build()
10965
}
11066

11167
/// Checks if the context is still valid.

rclrs/src/context/builder.rs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,71 @@
1+
use crate::error::ToResult;
12
use crate::rcl_bindings::*;
23
use crate::{Context, RclrsError};
34
use std::ffi::CString;
4-
use std::os::raw::c_char;
5+
use std::sync::Arc;
6+
57
use parking_lot::Mutex;
8+
use std::os::raw::c_char;
69

710
pub struct ContextBuilder {
811
cstring_args: Vec<CString>,
9-
c_args: Option<Vec<*const c_char>>,
10-
context_mtx: Mutex<rcl_context_t>,
11-
allocator: rcl_allocator_t,
1212
init_options_mtx: Mutex<rcl_init_options_t>,
1313
}
1414

1515
impl ContextBuilder {
16-
1716
/// Build a new ContextBuilder instance
1817
pub fn new(args: impl IntoIterator<Item = String>) -> Result<ContextBuilder, RclrsError> {
19-
unsafe {
20-
Ok(ContextBuilder {
21-
cstring_args: args.into_iter().map(|arg| {
22-
CString::new(arg.as_str()).map_err(|err| RclrsError::StringContainsNul{
18+
Ok(ContextBuilder {
19+
cstring_args: args
20+
.into_iter()
21+
.map(|arg| {
22+
CString::new(arg.as_str()).map_err(|err| RclrsError::StringContainsNul {
2323
err,
2424
s: arg.clone(),
2525
})
26-
}).collect::<Result<_, _>>()?,
27-
c_args: None, // to be built in the build function
28-
context_mtx: Mutex::new(rcl_get_zero_initialized_context()),
29-
allocator: rcutils_get_default_allocator(),
30-
init_options_mtx: Mutex::new(rcl_get_zero_initialized_init_options())
31-
})
32-
}
26+
})
27+
.collect::<Result<_, _>>()?,
28+
// SAFETY: Getting a zero-initialized value is always safe.
29+
init_options_mtx: unsafe { Mutex::new(rcl_get_zero_initialized_init_options()) },
30+
})
3331
}
3432

33+
/// Function to build the Context instance
3534
pub fn build(&self) -> Result<Context, RclrsError> {
36-
todo!("call build here");
35+
let mut rcl_init_options = self.init_options_mtx.lock();
36+
37+
let c_args: Vec<*const c_char> = self.cstring_args.iter().map(|arg| arg.as_ptr()).collect();
38+
unsafe {
39+
// SAFETY: Getting a zero-initialized value is always safe
40+
let mut rcl_context: rcl_context_t = rcl_get_zero_initialized_context();
41+
// SAFETY: No preconditions for this function.
42+
let allocator: rcutils_allocator_t = rcutils_get_default_allocator();
43+
44+
// SAFETY: Passing in a zero-initialized value is expected.
45+
// In the case where this returns not ok, there's nothing to clean up.
46+
rcl_init_options_init(&mut *rcl_init_options, allocator).ok()?;
47+
// SAFETY: This function does not store the ephemeral init_options and c_args
48+
// pointers. Passing in a zero-initialized rcl_context is expected.
49+
50+
let ret = rcl_init(
51+
c_args.len() as i32,
52+
if c_args.is_empty() {
53+
std::ptr::null()
54+
} else {
55+
c_args.as_ptr()
56+
},
57+
&*rcl_init_options,
58+
&mut rcl_context,
59+
)
60+
.ok();
61+
// SAFETY: It's safe to pass in an initialized object.
62+
// Early return will not leak memory, because this is the last fini function.
63+
rcl_init_options_fini(&mut *rcl_init_options).ok()?;
64+
// Move the check after the last fini()
65+
ret?;
66+
Ok(Context {
67+
rcl_context_mtx: Arc::new(Mutex::new(rcl_context)),
68+
})
69+
}
3770
}
3871
}

0 commit comments

Comments
 (0)