robotrt-cli 0.1.0-beta.1

RobotRT modular robotics runtime and middleware components.
use data_model::Packet;
use replay_core::{RecordedEntry, ReplaySpeed};

pub fn entry_to_json(entry: &RecordedEntry) -> serde_json::Value {
    match &entry.packet {
        Packet::Control(control) => serde_json::json!({
            "topic": entry.topic,
            "captured_at_unix_nanos": entry.captured_at.0,
            "kind": "control",
            "sequence": control.header.sequence,
            "label": control.label,
            "payload": String::from_utf8_lossy(&control.payload),
        }),
        Packet::Data(data) => serde_json::json!({
            "topic": entry.topic,
            "captured_at_unix_nanos": entry.captured_at.0,
            "kind": "data",
            "sequence": data.header.sequence,
            "payload": format!("{:?}", data.payload),
        }),
    }
}

pub fn parse_replay_speed(value: Option<String>) -> Result<ReplaySpeed, String> {
    let Some(raw) = value else {
        return Ok(ReplaySpeed::Instant);
    };
    match raw.as_str() {
        "instant" => Ok(ReplaySpeed::Instant),
        "realtime" => Ok(ReplaySpeed::RealTime),
        _ => {
            let factor = raw
                .parse::<f64>()
                .map_err(|err| format!("invalid --speed value: {raw} ({err})"))?;
            if factor <= 0.0 {
                return Err(format!("invalid --speed value: {raw} (must be > 0)"));
            }
            Ok(ReplaySpeed::Factor(factor))
        }
    }
}

pub fn replay_speed_label(speed: &ReplaySpeed) -> String {
    match speed {
        ReplaySpeed::Instant => "instant".to_string(),
        ReplaySpeed::RealTime => "realtime".to_string(),
        ReplaySpeed::Factor(value) => format!("factor:{value}"),
    }
}