rclrust 0.0.2

ROS2 client written in Rust
use anyhow::{Context, Result};

use crate::client::RclClient;
use crate::context::RclContext;
use crate::error::ToRclRustResult;
use crate::log::Logger;
use crate::rclrust_error;
use crate::service::RclService;
use crate::subscription::RclSubscription;
use crate::timer::RclTimer;

#[derive(Debug)]
pub(crate) struct RclWaitSet(rcl_sys::rcl_wait_set_t);

impl RclWaitSet {
    pub fn new(
        context: &mut RclContext,
        n_subscriptions: usize,
        n_guard_conditions: usize,
        n_timers: usize,
        n_clients: usize,
        n_services: usize,
        n_events: usize,
    ) -> Result<Self> {
        let mut wait_set = unsafe { rcl_sys::rcl_get_zero_initialized_wait_set() };

        unsafe {
            rcl_sys::rcl_wait_set_init(
                &mut wait_set,
                n_subscriptions,
                n_guard_conditions,
                n_timers,
                n_clients,
                n_services,
                n_events,
                context.raw_mut(),
                rcl_sys::rcutils_get_default_allocator(),
            )
            .to_result()
            .with_context(|| "rcl_sys::rcl_wait_set_init in RclWaitSet::new")?;
        }

        Ok(Self(wait_set))
    }

    pub fn wait(&mut self, timeout: i64) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait(&mut self.0, timeout)
                .to_result()
                .with_context(|| "rcl_sys::rcl_wait in RclWaitSet::wait")
        }
    }

    #[allow(unused)]
    fn is_valid(&self) -> bool {
        unsafe { rcl_sys::rcl_wait_set_is_valid(&self.0) }
    }

    pub fn clear(&mut self) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait_set_clear(&mut self.0)
                .to_result()
                .with_context(|| "rcl_sys::rcl_wait_set_clear in RclWaitSet::clear")
        }
    }

    pub fn add_subscription(&mut self, subscription: &RclSubscription) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait_set_add_subscription(
                &mut self.0,
                subscription.raw(),
                std::ptr::null_mut(),
            )
            .to_result()
            .with_context(|| {
                "rcl_sys::rcl_wait_set_add_subscription in RclWaitSet::add_subscription"
            })
        }
    }

    pub fn add_timer(&mut self, timer: &RclTimer) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait_set_add_timer(&mut self.0, timer.raw(), std::ptr::null_mut())
                .to_result()
                .with_context(|| "rcl_sys::rcl_wait_set_add_timer in RclWaitSet::add_timer")
        }
    }

    pub fn add_client(&mut self, client: &RclClient) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait_set_add_client(&mut self.0, client.raw(), std::ptr::null_mut())
                .to_result()
                .with_context(|| "rcl_sys::rcl_wait_set_add_client in RclWaitSet::add_client")
        }
    }

    pub fn add_service(&mut self, service: &RclService) -> Result<()> {
        unsafe {
            rcl_sys::rcl_wait_set_add_service(&mut self.0, service.raw(), std::ptr::null_mut())
                .to_result()
                .with_context(|| "rcl_sys::rcl_wait_set_add_service in RclWaitSet::add_service")
        }
    }
}

impl Drop for RclWaitSet {
    fn drop(&mut self) {
        if let Err(e) = unsafe { rcl_sys::rcl_wait_set_fini(&mut self.0).to_result() } {
            rclrust_error!(
                Logger::new("rclrust"),
                "rcl_wait_set_fini should succeed. {}",
                e
            );
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_rcl_wait_set_new() -> Result<()> {
        let ctx = crate::init()?;
        let wait_set = RclWaitSet::new(&mut ctx.handle.lock().unwrap(), 1, 1, 1, 1, 1, 1)?;
        assert!(wait_set.is_valid());

        Ok(())
    }

    #[test]
    fn test_rcl_wait_set_clear() -> Result<()> {
        let ctx = crate::init()?;
        let mut wait_set = RclWaitSet::new(&mut ctx.handle.lock().unwrap(), 1, 1, 1, 1, 1, 1)?;
        wait_set.clear()?;

        Ok(())
    }
}