openipc-web 0.1.28

WebAssembly bindings for openipc-rs
Documentation
use js_sys::{Object, Reflect, Uint8Array};
use openipc_core::FecCounters;
use wasm_bindgen::prelude::*;

pub(crate) fn raw_payload_object(payload: openipc_core::RoutePayload) -> Result<Object, JsValue> {
    let object = Object::new();
    Reflect::set(
        &object,
        &JsValue::from_str("data"),
        &Uint8Array::from(payload.data.as_slice()),
    )?;
    Reflect::set(
        &object,
        &JsValue::from_str("packetSeq"),
        &JsValue::from_str(&payload.packet_seq.to_string()),
    )?;
    set_number(&object, "routeId", payload.route_id.raw() as f64)?;
    set_number(&object, "channelId", payload.channel_id.raw() as f64)?;
    Ok(object)
}

pub(crate) fn set_number(object: &Object, key: &str, value: f64) -> Result<(), JsValue> {
    Reflect::set(object, &JsValue::from_str(key), &JsValue::from_f64(value))?;
    Ok(())
}

pub(crate) fn now_ms() -> f64 {
    #[cfg(target_arch = "wasm32")]
    {
        web_sys::window()
            .and_then(|window| window.performance())
            .map(|performance| performance.now())
            .unwrap_or_else(js_sys::Date::now)
    }
    #[cfg(not(target_arch = "wasm32"))]
    {
        0.0
    }
}

pub(crate) fn elapsed_ms(start_ms: f64) -> f64 {
    let elapsed = now_ms() - start_ms;
    if elapsed.is_finite() && elapsed >= 0.0 {
        elapsed
    } else {
        0.0
    }
}

pub(crate) fn counters_json(counters: FecCounters) -> String {
    format!(
        r#"{{"totalPackets":{},"recoveredPackets":{},"lostPackets":{},"badPackets":{}}}"#,
        counters.total_packets,
        counters.recovered_packets,
        counters.lost_packets,
        counters.bad_packets
    )
}

pub(crate) fn counters_object(counters: FecCounters) -> Result<Object, JsValue> {
    let object = Object::new();
    set_number(&object, "totalPackets", counters.total_packets as f64)?;
    set_number(
        &object,
        "recoveredPackets",
        counters.recovered_packets as f64,
    )?;
    set_number(&object, "lostPackets", counters.lost_packets as f64)?;
    set_number(&object, "badPackets", counters.bad_packets as f64)?;
    Ok(object)
}

pub(crate) fn escape_json_str(value: &str) -> String {
    let mut out = String::with_capacity(value.len());
    for ch in value.chars() {
        match ch {
            '"' => out.push_str("\\\""),
            '\\' => out.push_str("\\\\"),
            '\n' => out.push_str("\\n"),
            '\r' => out.push_str("\\r"),
            '\t' => out.push_str("\\t"),
            _ => out.push(ch),
        }
    }
    out
}

pub(crate) fn ms_from_js(now_ms: f64) -> u64 {
    if now_ms.is_finite() && now_ms > 0.0 {
        now_ms.min(u64::MAX as f64) as u64
    } else {
        0
    }
}

pub(crate) fn parse_hex_u64(input: &str) -> Result<u64, JsValue> {
    let trimmed = input.trim();
    let hex = trimmed
        .strip_prefix("0x")
        .or_else(|| trimmed.strip_prefix("0X"))
        .unwrap_or(trimmed);
    u64::from_str_radix(hex, 16)
        .map_err(|err| JsValue::from_str(&format!("invalid nonce hex: {err}")))
}