Skip to content

Commit

Permalink
Merge branch 'ros2-rust:main' into better_error_handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Guelakais authored Oct 1, 2024
2 parents 0c2bb70 + 5903d73 commit e7e5a28
Show file tree
Hide file tree
Showing 8 changed files with 615 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
run: |
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
. install/setup.sh
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" { print $2 }'); do
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" && $1 != "rust_pubsub" { print $2 }'); do
cd $path
echo "Running cargo test in $path"
# Run cargo test for all features except generate_docs (needed for docs.rs)
Expand All @@ -119,7 +119,7 @@ jobs:
run: |
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
. /opt/ros/${{ matrix.ros_distribution }}/setup.sh
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" { print $2 }'); do
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" && $1 != "rust_pubsub" { print $2 }'); do
cd $path
echo "Running rustdoc check in $path"
cargo rustdoc -- -D warnings
Expand Down
469 changes: 469 additions & 0 deletions docs/writing_a_simple_publisher_and_subscriber.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions examples/rust_pubsub/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "rust_pubsub"
version = "0.1.0"
edition = "2021"

[[bin]]
name="simple_publisher"
path="src/simple_publisher.rs"

[[bin]]
name="simple_subscriber"
path="src/simple_subscriber.rs"

[dependencies]
rclrs = "*"
std_msgs = "*"
14 changes: 14 additions & 0 deletions examples/rust_pubsub/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<package format="3">
<name>rust_pubsub</name>
<version>0.0.0</version>
<description>TODO: Package description.</description>
<maintainer email="user@todo.todo">user</maintainer>
<license>TODO: License declaration.</license>

<depend>rclrs</depend>
<depend>std_msgs</depend>

<export>
<build_type>ament_cargo</build_type>
</export>
</package>
36 changes: 36 additions & 0 deletions examples/rust_pubsub/src/simple_publisher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use rclrs::{create_node, Context, Node, Publisher, RclrsError, QOS_PROFILE_DEFAULT};
use std::{sync::Arc, thread, time::Duration};
use std_msgs::msg::String as StringMsg;
struct SimplePublisherNode {
node: Arc<Node>,
_publisher: Arc<Publisher<StringMsg>>,
}
impl SimplePublisherNode {
fn new(context: &Context) -> Result<Self, RclrsError> {
let node = create_node(context, "simple_publisher").unwrap();
let _publisher = node
.create_publisher("publish_hello", QOS_PROFILE_DEFAULT)
.unwrap();
Ok(Self { node, _publisher })
}

fn publish_data(&self, increment: i32) -> Result<i32, RclrsError> {
let msg: StringMsg = StringMsg {
data: format!("Hello World {}", increment),
};
self._publisher.publish(msg).unwrap();
Ok(increment + 1_i32)
}
}

fn main() -> Result<(), RclrsError> {
let context = Context::new(std::env::args()).unwrap();
let publisher = Arc::new(SimplePublisherNode::new(&context).unwrap());
let publisher_other_thread = Arc::clone(&publisher);
let mut count: i32 = 0;
thread::spawn(move || loop {
thread::sleep(Duration::from_millis(1000));
count = publisher_other_thread.publish_data(count).unwrap();
});
rclrs::spin(publisher.node.clone())
}
52 changes: 52 additions & 0 deletions examples/rust_pubsub/src/simple_subscriber.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use rclrs::{create_node, Context, Node, RclrsError, Subscription, QOS_PROFILE_DEFAULT};
use std::{
env,
sync::{Arc, Mutex},
thread,
time::Duration,
};
use std_msgs::msg::String as StringMsg;
pub struct SimpleSubscriptionNode {
node: Arc<Node>,
_subscriber: Arc<Subscription<StringMsg>>,
data: Arc<Mutex<Option<StringMsg>>>,
}
impl SimpleSubscriptionNode {
fn new(context: &Context) -> Result<Self, RclrsError> {
let node = create_node(context, "simple_subscription").unwrap();
let data: Arc<Mutex<Option<StringMsg>>> = Arc::new(Mutex::new(None));
let data_mut: Arc<Mutex<Option<StringMsg>>> = Arc::clone(&data);
let _subscriber = node
.create_subscription::<StringMsg, _>(
"publish_hello",
QOS_PROFILE_DEFAULT,
move |msg: StringMsg| {
*data_mut.lock().unwrap() = Some(msg);
},
)
.unwrap();
Ok(Self {
node,
_subscriber,
data,
})
}
fn data_callback(&self) -> Result<(), RclrsError> {
if let Some(data) = self.data.lock().unwrap().as_ref() {
println!("{}", data.data);
} else {
println!("No message available yet.");
}
Ok(())
}
}
fn main() -> Result<(), RclrsError> {
let context = Context::new(env::args()).unwrap();
let subscription = Arc::new(SimpleSubscriptionNode::new(&context).unwrap());
let subscription_other_thread = Arc::clone(&subscription);
thread::spawn(move || loop {
thread::sleep(Duration::from_millis(1000));
subscription_other_thread.data_callback().unwrap()
});
rclrs::spin(subscription.node.clone())
}
4 changes: 2 additions & 2 deletions rclrs/src/parameter/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ fn get_parameters(req: GetParameters_Request, map: &ParameterMap) -> GetParamete
}

fn list_parameters(req: ListParameters_Request, map: &ParameterMap) -> ListParameters_Response {
let check_parameter_name_depth = |substring: &[i8]| {
let check_parameter_name_depth = |substring: &[std::os::raw::c_char]| {
if req.depth == ListParameters_Request::DEPTH_RECURSIVE {
return true;
}
u64::try_from(substring.iter().filter(|c| **c == ('.' as i8)).count()).unwrap() < req.depth
u64::try_from(substring.iter().filter(|c| **c == ('.' as _)).count()).unwrap() < req.depth
};
let names: Sequence<_> = map
.storage
Expand Down
32 changes: 24 additions & 8 deletions rosidl_runtime_rs/src/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,18 +309,26 @@ where
///
/// Equivalent to `&seq[..]`.
pub fn as_slice(&self) -> &[T] {
// SAFETY: self.data points to self.size consecutive, initialized elements and
// isn't modified externally.
unsafe { std::slice::from_raw_parts(self.data, self.size) }
if self.data.is_null() {
&[]
} else {
// SAFETY: self.data is not null and points to self.size consecutive,
// initialized elements and isn't modified externally.
unsafe { std::slice::from_raw_parts(self.data, self.size) }
}
}

/// Extracts a mutable slice containing the entire sequence.
///
/// Equivalent to `&mut seq[..]`.
pub fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: self.data points to self.size consecutive, initialized elements and
// isn't modified externally.
unsafe { std::slice::from_raw_parts_mut(self.data, self.size) }
if self.data.is_null() {
&mut []
} else {
// SAFETY: self.data is not null and points to self.size consecutive,
// initialized elements and isn't modified externally.
unsafe { std::slice::from_raw_parts_mut(self.data, self.size) }
}
}
}

Expand Down Expand Up @@ -602,8 +610,10 @@ macro_rules! impl_sequence_alloc_for_primitive_type {
unsafe {
// This allocates space and sets seq.size and seq.capacity to size
let ret = $init_func(seq as *mut _, size);
// Zero memory, since it will be uninitialized if there is no default value
std::ptr::write_bytes(seq.data, 0u8, size);
if !seq.data.is_null() {
// Zero memory, since it will be uninitialized if there is no default value
std::ptr::write_bytes(seq.data, 0u8, size);
}
ret
}
}
Expand Down Expand Up @@ -783,6 +793,12 @@ mod tests {
}
}

#[test]
fn test_empty_sequence() {
assert!(Sequence::<i32>::default().is_empty());
assert!(BoundedSequence::<i32, 5>::default().is_empty());
}

quickcheck! {
fn test_extend(xs: Vec<i32>, ys: Vec<i32>) -> bool {
let mut xs_seq = Sequence::new(xs.len());
Expand Down

0 comments on commit e7e5a28

Please sign in to comment.