openrtc 1.0.1

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
//! Canonical transport label taxonomy.
//!
//! Peer snapshots, native send routing, and optional transport projection all
//! exchange labels as strings across Rust, WASM, TS, and IPC. Keep normalization
//! and classification in one target-neutral place so cross-platform behavior
//! cannot drift one call site at a time.

pub(crate) const IROH: &str = "iroh";
pub(crate) const IROH_QUIC: &str = "iroh-quic";
pub(crate) const IROH_RELAY: &str = "iroh-relay";
pub(crate) const IROH_LAN: &str = "iroh-lan";
pub(crate) const BLE: &str = "ble";
pub(crate) const WEBRTC: &str = "webrtc";
pub(crate) const WEBRTC_LAN: &str = "webrtc-lan";
pub(crate) const MOQ: &str = "moq";

pub(crate) fn normalize(value: &str) -> Option<&'static str> {
    match value.trim().to_ascii_lowercase().as_str() {
        IROH => Some(IROH),
        IROH_QUIC => Some(IROH_QUIC),
        IROH_RELAY => Some(IROH_RELAY),
        IROH_LAN => Some(IROH_LAN),
        BLE => Some(BLE),
        WEBRTC => Some(WEBRTC),
        WEBRTC_LAN => Some(WEBRTC_LAN),
        MOQ => Some(MOQ),
        _ => None,
    }
}

#[allow(dead_code)]
pub(crate) fn is_iroh_base(value: &str) -> bool {
    matches!(
        normalize(value),
        Some(IROH | IROH_QUIC | IROH_LAN | IROH_RELAY | BLE)
    )
}

#[allow(dead_code)]
pub(crate) fn is_direct_iroh(value: &str) -> bool {
    matches!(normalize(value), Some(IROH_QUIC | IROH_LAN | BLE))
}

#[allow(dead_code)]
pub(crate) fn is_optional(value: &str) -> bool {
    matches!(normalize(value), Some(WEBRTC | WEBRTC_LAN | MOQ))
}

#[allow(dead_code)]
pub(crate) fn is_webrtc(value: &str) -> bool {
    matches!(normalize(value), Some(WEBRTC | WEBRTC_LAN))
}

pub(crate) fn is_independent_transport(value: &str) -> bool {
    matches!(normalize(value), Some(WEBRTC | MOQ))
}

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

    #[derive(serde::Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct TransportPolicyVectors {
        labels: Vec<LabelVector>,
    }

    #[derive(serde::Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct LabelVector {
        input: String,
        normalized: Option<String>,
        iroh_base: bool,
        direct_iroh: bool,
        optional: bool,
        web_rtc: bool,
        independent: bool,
    }

    #[test]
    fn normalizes_official_labels_case_insensitively() {
        for (input, expected) in [
            ("iroh", IROH),
            (" IROH-QUIC ", IROH_QUIC),
            ("iroh-relay", IROH_RELAY),
            ("iroh-lan", IROH_LAN),
            ("ble", BLE),
            ("webrtc", WEBRTC),
            ("webrtc-lan", WEBRTC_LAN),
            ("moq", MOQ),
        ] {
            assert_eq!(normalize(input), Some(expected));
        }
        assert_eq!(normalize("lan"), None);
        assert_eq!(normalize("webtransport"), None);
    }

    #[test]
    fn classifies_transport_families() {
        assert!(is_iroh_base(IROH));
        assert!(is_iroh_base(IROH_QUIC));
        assert!(is_iroh_base(IROH_LAN));
        assert!(is_iroh_base(IROH_RELAY));
        assert!(is_iroh_base(BLE));
        assert!(!is_iroh_base(WEBRTC));

        assert!(is_direct_iroh(IROH_QUIC));
        assert!(is_direct_iroh(IROH_LAN));
        assert!(is_direct_iroh(BLE));
        assert!(!is_direct_iroh(IROH_RELAY));

        assert!(is_optional(WEBRTC));
        assert!(is_optional(WEBRTC_LAN));
        assert!(is_optional(MOQ));
        assert!(!is_optional(IROH_QUIC));

        assert!(is_webrtc(WEBRTC));
        assert!(is_webrtc(WEBRTC_LAN));
        assert!(!is_webrtc(MOQ));

        assert!(is_independent_transport(WEBRTC));
        assert!(is_independent_transport(MOQ));
        assert!(!is_independent_transport(WEBRTC_LAN));
    }

    #[test]
    fn matches_shared_transport_policy_vectors() {
        let vectors: TransportPolicyVectors =
            serde_json::from_str(include_str!("../testdata/transport_policy_vectors.json"))
                .expect("transport policy vectors");
        for vector in vectors.labels {
            assert_eq!(
                normalize(&vector.input),
                vector.normalized.as_deref(),
                "normalize({:?})",
                vector.input
            );
            assert_eq!(
                is_iroh_base(&vector.input),
                vector.iroh_base,
                "is_iroh_base({:?})",
                vector.input
            );
            assert_eq!(
                is_direct_iroh(&vector.input),
                vector.direct_iroh,
                "is_direct_iroh({:?})",
                vector.input
            );
            assert_eq!(
                is_optional(&vector.input),
                vector.optional,
                "is_optional({:?})",
                vector.input
            );
            assert_eq!(
                is_webrtc(&vector.input),
                vector.web_rtc,
                "is_webrtc({:?})",
                vector.input
            );
            assert_eq!(
                is_independent_transport(&vector.input),
                vector.independent,
                "is_independent_transport({:?})",
                vector.input
            );
        }
    }
}