cu-ros2-payloads 1.0.1

ROS2 Payloads that can be constructed from/to Copper Payloads for compatibility
Documentation
use std::process::Command;
use std::thread;

use cu_ros2_payloads::RosBridgeAdapter;
use cu_ros2_payloads::builtin::{Header, Time};
use cu_ros2_payloads::sensor_msgs::{PointCloud2, PointField};
use cu_sensor_payloads::{PointCloudSoa, PointCloudSoaHandle};

const HELPER_ENV: &str = "CU_ROS2_POINTCLOUD_STACK_HELPER";
const LARGE_POINTS: usize = 200_000;
const SMALL_STACK_BYTES: usize = 256 * 1024;

fn large_pointcloud2() -> PointCloud2 {
    let width = LARGE_POINTS as u32;
    let point_step = 24u32;
    let row_step = width * point_step;
    PointCloud2 {
        header: Header {
            stamp: Time { sec: 0, nanosec: 0 },
            frame_id: "".into(),
        },
        height: 1,
        width,
        fields: vec![
            PointField {
                name: "x".into(),
                offset: 0,
                datatype: 7,
                count: 1,
            },
            PointField {
                name: "y".into(),
                offset: 4,
                datatype: 7,
                count: 1,
            },
            PointField {
                name: "z".into(),
                offset: 8,
                datatype: 7,
                count: 1,
            },
            PointField {
                name: "intensity".into(),
                offset: 12,
                datatype: 7,
                count: 1,
            },
            PointField {
                name: "tov_sec".into(),
                offset: 16,
                datatype: 6,
                count: 1,
            },
            PointField {
                name: "tov_nsec".into(),
                offset: 20,
                datatype: 6,
                count: 1,
            },
        ],
        is_bigendian: false,
        point_step,
        row_step,
        data: vec![0u8; row_step as usize],
        is_dense: true,
    }
}

fn run_handle_decode_on_small_stack() {
    let ros = large_pointcloud2();
    thread::Builder::new()
        .stack_size(SMALL_STACK_BYTES)
        .spawn(move || {
            let payload = PointCloudSoaHandle::<LARGE_POINTS>::from_ros_message(ros)
                .expect("handle decode should succeed");
            payload.with_inner(|inner| assert_eq!(inner.len, LARGE_POINTS));
        })
        .expect("thread spawn should succeed")
        .join()
        .expect("handle decode thread should not panic");
}

#[cfg(target_os = "linux")]
fn run_soa_decode_on_small_stack() {
    let ros = large_pointcloud2();
    thread::Builder::new()
        .stack_size(SMALL_STACK_BYTES)
        .spawn(move || {
            let _ = PointCloudSoa::<LARGE_POINTS>::from_ros_message(ros)
                .expect("SoA decode should run");
        })
        .expect("thread spawn should succeed")
        .join()
        .expect("SoA decode thread should not panic");
}

fn run_self(test_name: &str, helper_mode: &str) -> std::process::ExitStatus {
    Command::new(std::env::current_exe().expect("current_exe should succeed"))
        .arg("--exact")
        .arg(test_name)
        .env(HELPER_ENV, helper_mode)
        .status()
        .expect("child test process should launch")
}

#[test]
fn handled_pointcloud_decode_survives_small_stack() {
    if std::env::var(HELPER_ENV).ok().as_deref() == Some("handled") {
        run_handle_decode_on_small_stack();
        return;
    }

    let status = run_self("handled_pointcloud_decode_survives_small_stack", "handled");
    assert!(
        status.success(),
        "handled child should succeed, got {status:?}"
    );
}

#[cfg(target_os = "linux")]
#[test]
fn soa_pointcloud_decode_overflows_small_stack_subprocess() {
    if std::env::var(HELPER_ENV).ok().as_deref() == Some("soa") {
        run_soa_decode_on_small_stack();
        return;
    }

    let status = run_self(
        "soa_pointcloud_decode_overflows_small_stack_subprocess",
        "soa",
    );
    assert!(
        !status.success(),
        "expected SoA child decode to fail on a small stack, got {status:?}"
    );
}