Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/generate-bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
use-ros2-testing: ${{ matrix.ros_distribution == 'rolling' }}

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.75
uses: dtolnay/rust-toolchain@1.85
with:
components: clippy, rustfmt

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rust-minimal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
use-ros2-testing: ${{ matrix.ros_distribution == 'rolling' }}

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.75
uses: dtolnay/rust-toolchain@1.85
with:
components: clippy, rustfmt

Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/rust-win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Get pixi toml file
run: irm https://raw.githubusercontent.com/ros2/ros2/refs/heads/rolling/pixi.toml -OutFile C:\pixi_ws\pixi.toml

- name: Setup Pixi environment woth ROS2 toml file
- name: Setup Pixi environment with ROS 2 toml file
uses: prefix-dev/[email protected]
with:
manifest-path: C:/pixi_ws/pixi.toml
Expand All @@ -49,7 +49,7 @@ jobs:
pixi add --pypi "colcon-cargo@git+https://github.com/colcon/colcon-cargo.git" --manifest-path C:\pixi_ws\pixi.toml
pixi upgrade colcon-core --manifest-path C:\pixi_ws\pixi.toml

- name: Get prebuild ROS files and unzip
- name: Get prebuilt ROS files and unzip
run: |
irm https://github.com/knmcguire/ros2/releases/download/temp_win_v.0.0.1/ros2-package-windows-AMD64.zip -Outfile ros2-package-windows-AMD64.zip
Expand-Archive -Path ros2-package-windows-AMD64.zip -DestinationPath C:/pixi_ws/
Expand All @@ -60,6 +60,8 @@ jobs:
BINDGEN_EXTRA_CLANG_ARGS: -D_Check_return_= # to handle the clang error with the windows specific bindgen error
run: |
call C:\pixi_ws\ros2-windows\setup.bat
pixi remove rust --manifest-path C:\pixi_ws\pixi.toml
pixi add "rust==1.85.0" --manifest-path C:\pixi_ws\pixi.toml
pixi run --manifest-path C:\pixi_ws\pixi.toml vcs import C:/workspace/src --input C:/workspace/src/ros2_rust/ros2_rust_rolling.repos
pixi run --manifest-path C:\pixi_ws\pixi.toml colcon build
working-directory: C:/workspace
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/*

# Install Rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.75.0 -y
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.85.0 -y
ENV PATH=/root/.cargo/bin:$PATH

COPY src/ros2_rust/docker/install_colcon_plugins.sh /
Expand Down
2 changes: 1 addition & 1 deletion rclrs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["Esteve Fernandez <[email protected]>", "Nikolai Morin <nnmmgit@gmail
edition = "2021"
license = "Apache-2.0"
description = "A ROS 2 client library for developing robotics applications in Rust"
rust-version = "1.75"
rust-version = "1.85"

[lib]
path = "src/lib.rs"
Expand Down
2 changes: 1 addition & 1 deletion rclrs/generate_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def main():
bindgen_command.append('--rust-edition')
bindgen_command.append('2021')
bindgen_command.append('--rust-target')
bindgen_command.append('1.75')
bindgen_command.append('1.85')
bindgen_command.append('--no-derive-copy')
bindgen_command.append('--allowlist-type')
bindgen_command.append('rcl_.*')
Expand Down
2 changes: 1 addition & 1 deletion rclrs/src/logging/logging_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub(crate) mod log_handler {

/// This function exists so that we can give a raw function pointer to
/// rcutils_logging_set_output_handler, which is needed by its API.
extern "C" fn rclrs_logging_output_handler(
unsafe extern "C" fn rclrs_logging_output_handler(
location: *const rcutils_log_location_t,
severity: std::os::raw::c_int,
logger_name: *const std::os::raw::c_char,
Expand Down
18 changes: 10 additions & 8 deletions rclrs/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ impl NodeState {
/// ```
/// # use rclrs::*;
/// // Set default ROS domain ID to 10 here
/// std::env::set_var("ROS_DOMAIN_ID", "10");
/// unsafe { std::env::set_var("ROS_DOMAIN_ID", "10"); }
/// let executor = Context::default().create_basic_executor();
/// let node = executor.create_node("domain_id_node")?;
/// let domain_id = node.domain_id();
Expand Down Expand Up @@ -1509,13 +1509,15 @@ pub(crate) unsafe fn call_string_getter_with_rcl_node(
rcl_node: &rcl_node_t,
getter: unsafe extern "C" fn(*const rcl_node_t) -> *const c_char,
) -> String {
let char_ptr = getter(rcl_node);
debug_assert!(!char_ptr.is_null());
// SAFETY: The returned CStr is immediately converted to an owned string,
// so the lifetime is no issue. The ptr is valid as per the documentation
// of rcl_node_get_name.
let cstr = CStr::from_ptr(char_ptr);
cstr.to_string_lossy().into_owned()
unsafe {
let char_ptr = getter(rcl_node);
debug_assert!(!char_ptr.is_null());
// SAFETY: The returned CStr is immediately converted to an owned string,
// so the lifetime is no issue. The ptr is valid as per the documentation
// of rcl_node_get_name.
let cstr = CStr::from_ptr(char_ptr);
cstr.to_string_lossy().into_owned()
}
}

// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
Expand Down
36 changes: 20 additions & 16 deletions rclrs/src/node/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,16 @@ impl NodeState {
node_namespace: *const ::std::os::raw::c_char,
topic_names_and_types: *mut rcl_names_and_types_t,
) -> rcl_ret_t {
rcl_get_publisher_names_and_types_by_node(
node,
allocator,
false,
node_name,
node_namespace,
topic_names_and_types,
)
unsafe {
rcl_get_publisher_names_and_types_by_node(
node,
allocator,
false,
node_name,
node_namespace,
topic_names_and_types,
)
}
}

self.get_names_and_types_by_node(node, namespace, wrapper)
Expand All @@ -99,14 +101,16 @@ impl NodeState {
node_namespace: *const ::std::os::raw::c_char,
topic_names_and_types: *mut rcl_names_and_types_t,
) -> rcl_ret_t {
rcl_get_subscriber_names_and_types_by_node(
node,
allocator,
false,
node_name,
node_namespace,
topic_names_and_types,
)
unsafe {
rcl_get_subscriber_names_and_types_by_node(
node,
allocator,
false,
node_name,
node_namespace,
topic_names_and_types,
)
}
}

self.get_names_and_types_by_node(node, namespace, wrapper)
Expand Down
55 changes: 31 additions & 24 deletions rclrs/src/parameter/override_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ impl RclParamsIter<'_> {
rcl_node_params: &[],
}
} else {
let node_name_ptrs =
rcl_from_raw_parts((*rcl_params).node_names, (*rcl_params).num_nodes);
let rcl_node_params = rcl_from_raw_parts((*rcl_params).params, (*rcl_params).num_nodes);
Self {
node_name_ptrs,
rcl_node_params,
unsafe {
let node_name_ptrs =
rcl_from_raw_parts((*rcl_params).node_names, (*rcl_params).num_nodes);
let rcl_node_params =
rcl_from_raw_parts((*rcl_params).params, (*rcl_params).num_nodes);
Self {
node_name_ptrs,
rcl_node_params,
}
}
}
}
Expand Down Expand Up @@ -81,10 +84,12 @@ impl<'a> RclNodeParamsIter<'a> {
// This function is unsafe since the rcl_node_params argument might contain incorrect array
// sizes or dangling pointers.
pub unsafe fn new(rcl_node_params: &'a rcl_node_params_t) -> Self {
let param_name_ptrs =
rcl_from_raw_parts(rcl_node_params.parameter_names, rcl_node_params.num_params);
let rcl_variants =
rcl_from_raw_parts(rcl_node_params.parameter_values, rcl_node_params.num_params);
let param_name_ptrs = unsafe {
rcl_from_raw_parts(rcl_node_params.parameter_names, rcl_node_params.num_params)
};
let rcl_variants = unsafe {
rcl_from_raw_parts(rcl_node_params.parameter_values, rcl_node_params.num_params)
};
Self {
param_name_ptrs,
rcl_variants,
Expand All @@ -109,25 +114,27 @@ pub(crate) unsafe fn resolve_parameter_overrides(
rcl_node_arguments: &rcl_arguments_t,
rcl_global_arguments: &rcl_arguments_t,
) -> Result<ParameterOverrideMap, RclrsError> {
let mut map = BTreeMap::new();
for rcl_arguments in [rcl_global_arguments, rcl_node_arguments] {
let mut rcl_params = std::ptr::null_mut();
rcl_arguments_get_param_overrides(rcl_arguments, &mut rcl_params).ok()?;
// Check for the /** node first, and later overwrite with the more specific node
// parameters, if they exist
for name_to_match in ["/**", node_fqn] {
for (node_name, node_params) in RclParamsIter::new(rcl_params) {
if node_name == name_to_match {
for (param_name, variant) in RclNodeParamsIter::new(node_params) {
let value = ParameterValue::from_rcl_variant(variant);
map.insert(param_name, value);
unsafe {
let mut map = BTreeMap::new();
for rcl_arguments in [rcl_global_arguments, rcl_node_arguments] {
let mut rcl_params = std::ptr::null_mut();
rcl_arguments_get_param_overrides(rcl_arguments, &mut rcl_params).ok()?;
// Check for the /** node first, and later overwrite with the more specific node
// parameters, if they exist
for name_to_match in ["/**", node_fqn] {
for (node_name, node_params) in RclParamsIter::new(rcl_params) {
if node_name == name_to_match {
for (param_name, variant) in RclNodeParamsIter::new(node_params) {
let value = ParameterValue::from_rcl_variant(variant);
map.insert(param_name, value);
}
}
}
}
rcl_yaml_node_struct_fini(rcl_params);
}
rcl_yaml_node_struct_fini(rcl_params);
Ok(map)
}
Ok(map)
}

#[cfg(test)]
Expand Down
74 changes: 44 additions & 30 deletions rclrs/src/parameter/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ impl ParameterValue {
.map(u8::from)
.sum();
assert_eq!(num_active, 1);
// Note: This code has no unsafe blocks because it is inside an unsafe function.
// Note: Unsafe blocks below are necessary to dereference raw pointers
// and call unsafe functions like CStr::from_ptr.
// In general, the following operations are as safe as they can be, because
// only non-null pointers are dereferenced, and strings and arrays are copied immediately,
// so there are no concerns about choosing the correct lifetime.
Expand All @@ -462,43 +463,56 @@ impl ParameterValue {
// However, it cannot be checked that it points to a valid value. Similarly for array sizes.
// This is why this function must be unsafe itself.
if !var.bool_value.is_null() {
ParameterValue::Bool(*var.bool_value)
unsafe { ParameterValue::Bool(*var.bool_value) }
} else if !var.integer_value.is_null() {
ParameterValue::Integer(*var.integer_value)
unsafe { ParameterValue::Integer(*var.integer_value) }
} else if !var.double_value.is_null() {
ParameterValue::Double(*var.double_value)
unsafe { ParameterValue::Double(*var.double_value) }
} else if !var.string_value.is_null() {
let cstr = CStr::from_ptr(var.string_value);
let s = cstr.to_string_lossy().into_owned();
ParameterValue::String(s.into())
unsafe {
let cstr = CStr::from_ptr(var.string_value);
let s = cstr.to_string_lossy().into_owned();
ParameterValue::String(s.into())
}
} else if !var.byte_array_value.is_null() {
let rcl_byte_array = &*var.byte_array_value;
let slice = rcl_from_raw_parts(rcl_byte_array.values, rcl_byte_array.size);
ParameterValue::ByteArray(slice.into())
unsafe {
let rcl_byte_array = &*var.byte_array_value;
let slice = rcl_from_raw_parts(rcl_byte_array.values, rcl_byte_array.size);
ParameterValue::ByteArray(slice.into())
}
} else if !var.bool_array_value.is_null() {
let rcl_bool_array = &*var.bool_array_value;
let slice = rcl_from_raw_parts(rcl_bool_array.values, rcl_bool_array.size);
ParameterValue::BoolArray(slice.into())
unsafe {
let rcl_bool_array = &*var.bool_array_value;
let slice = rcl_from_raw_parts(rcl_bool_array.values, rcl_bool_array.size);
ParameterValue::BoolArray(slice.into())
}
} else if !var.integer_array_value.is_null() {
let rcl_integer_array = &*var.integer_array_value;
let slice = rcl_from_raw_parts(rcl_integer_array.values, rcl_integer_array.size);
ParameterValue::IntegerArray(slice.into())
unsafe {
let rcl_integer_array = &*var.integer_array_value;
let slice = rcl_from_raw_parts(rcl_integer_array.values, rcl_integer_array.size);
ParameterValue::IntegerArray(slice.into())
}
} else if !var.double_array_value.is_null() {
let rcl_double_array = &*var.double_array_value;
let slice = rcl_from_raw_parts(rcl_double_array.values, rcl_double_array.size);
ParameterValue::DoubleArray(slice.into())
unsafe {
let rcl_double_array = &*var.double_array_value;
let slice = rcl_from_raw_parts(rcl_double_array.values, rcl_double_array.size);
ParameterValue::DoubleArray(slice.into())
}
} else if !var.string_array_value.is_null() {
let rcutils_string_array = &*var.string_array_value;
let slice = rcl_from_raw_parts(rcutils_string_array.data, rcutils_string_array.size);
let strings = slice
.iter()
.map(|&ptr| {
debug_assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr);
Arc::from(cstr.to_string_lossy())
})
.collect::<Vec<_>>();
ParameterValue::StringArray(strings.into())
unsafe {
let rcutils_string_array = &*var.string_array_value;
let slice =
rcl_from_raw_parts(rcutils_string_array.data, rcutils_string_array.size);
let strings = slice
.iter()
.map(|&ptr| {
debug_assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr);
Arc::from(cstr.to_string_lossy())
})
.collect::<Vec<_>>();
ParameterValue::StringArray(strings.into())
}
} else {
unreachable!()
}
Expand Down
Loading