openrtc 1.0.2

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
//! Pure route selection policy shared by native Rust and browser WASM.
//!
//! This module only turns route labels into a deterministic ordering. It does
//! not inspect sockets, start retries, mutate lifecycle state, or report UI
//! status. The connection owner remains responsible for deciding which of the
//! returned candidates is actually usable.

pub use crate::generated::route_registry::{
    KnownRoute, RouteDescriptor, RouteFamily, RouteImplementation, RouteLocality, RouteMaturity,
    KNOWN_ROUTE_DESCRIPTORS,
};

/// Normalize a route label into one of the typed, known route descriptors.
pub fn normalize_route(value: &str) -> Option<KnownRoute> {
    let normalized = value.trim().to_ascii_lowercase();
    KNOWN_ROUTE_DESCRIPTORS
        .iter()
        .find(|descriptor| descriptor.id == normalized)
        .map(|descriptor| descriptor.route)
}

/// Normalize, deduplicate, and rank candidate route labels.
///
/// Unknown labels are omitted. Configured priority is honored by first
/// occurrence after normalization; candidates absent from that priority are
/// ordered by their stable default rank and then by their original candidate
/// position. An empty or entirely unknown configured priority uses the public
/// client default, preserving existing behavior.
pub fn rank_routes(configured_priority: &[String], candidates: &[String]) -> Vec<String> {
    let configured = unique_known(configured_priority);
    let priority = if configured.is_empty() {
        KnownRoute::DEFAULT_PRIORITY.to_vec()
    } else {
        configured
    };

    let candidates = unique_known(candidates);
    let mut ranked: Vec<(KnownRoute, usize)> = candidates
        .into_iter()
        .enumerate()
        .map(|(candidate_index, route)| (route, candidate_index))
        .collect();

    ranked.sort_by(|(left, left_index), (right, right_index)| {
        route_sort_key(*left, *left_index, &priority).cmp(&route_sort_key(
            *right,
            *right_index,
            &priority,
        ))
    });

    ranked
        .into_iter()
        .map(|(route, _)| route.as_str().to_string())
        .collect()
}

fn unique_known(values: &[String]) -> Vec<KnownRoute> {
    let mut result = Vec::new();
    for value in values {
        let Some(route) = normalize_route(value) else {
            continue;
        };
        if !result.contains(&route) {
            result.push(route);
        }
    }
    result
}

fn route_sort_key(
    route: KnownRoute,
    candidate_index: usize,
    configured_priority: &[KnownRoute],
) -> (u8, usize, u8, usize) {
    match configured_priority
        .iter()
        .position(|candidate| *candidate == route)
    {
        Some(configured_index) => (0, configured_index, route.default_rank(), candidate_index),
        None => (1, 0, route.default_rank(), candidate_index),
    }
}

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

    #[derive(Debug, serde::Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct PolicyVectors {
        routes: Vec<RegistryRoute>,
        default_priority: Vec<String>,
        rank_routes: Vec<RankRoutesVector>,
    }

    #[derive(Debug, serde::Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct RegistryRoute {
        id: String,
        base_protocol: String,
        family: String,
        implementation: String,
        locality: String,
        maturity: String,
        default_rank: u8,
        browser: bool,
        native: bool,
        independently_instantiable: bool,
    }

    #[derive(Debug, serde::Deserialize)]
    #[serde(rename_all = "camelCase")]
    struct RankRoutesVector {
        configured_priority: Vec<String>,
        candidates: Vec<String>,
        expected: Vec<String>,
    }

    #[test]
    fn known_route_descriptors_have_unique_stable_ranks() {
        let mut ranks: Vec<_> = KNOWN_ROUTE_DESCRIPTORS
            .iter()
            .map(|descriptor| descriptor.default_rank)
            .collect();
        ranks.sort_unstable();
        ranks.dedup();
        assert_eq!(ranks, (0..9).collect::<Vec<_>>());
    }

    #[test]
    fn generated_descriptors_match_the_canonical_registry() {
        let registry: PolicyVectors =
            serde_json::from_str(crate::generated::route_registry::TRANSPORT_REGISTRY_JSON)
                .expect("transport registry");
        assert_eq!(registry.routes.len(), KNOWN_ROUTE_DESCRIPTORS.len());

        for descriptor in KNOWN_ROUTE_DESCRIPTORS {
            let expected = registry
                .routes
                .iter()
                .find(|route| route.id == descriptor.id)
                .unwrap_or_else(|| panic!("missing registry route {}", descriptor.id));
            assert_eq!(expected.base_protocol, descriptor.base_protocol);
            assert_eq!(expected.default_rank, descriptor.default_rank);
            assert_eq!(expected.browser, descriptor.browser);
            assert_eq!(expected.native, descriptor.native);
            assert_eq!(
                expected.independently_instantiable,
                descriptor.independently_instantiable
            );
            assert_eq!(expected.family, serialized_name(descriptor.family));
            assert_eq!(
                expected.implementation,
                serialized_name(descriptor.implementation)
            );
            assert_eq!(expected.locality, serialized_name(descriptor.locality));
            assert_eq!(expected.maturity, serialized_name(descriptor.maturity));
        }

        assert_eq!(
            registry.default_priority,
            KnownRoute::DEFAULT_PRIORITY
                .iter()
                .map(|route| route.as_str().to_string())
                .collect::<Vec<_>>()
        );
    }

    fn serialized_name<T: serde::Serialize>(value: T) -> String {
        serde_json::to_value(value)
            .expect("serialize registry enum")
            .as_str()
            .expect("registry enum serializes as string")
            .to_string()
    }

    #[test]
    fn normalization_is_case_and_whitespace_insensitive() {
        assert_eq!(normalize_route(" IROH-QUIC "), Some(KnownRoute::IrohQuic));
        assert_eq!(normalize_route("WebRTC-LAN"), Some(KnownRoute::WebRtcLan));
        assert_eq!(normalize_route(" webtransport "), None);
    }

    #[test]
    fn ranking_deduplicates_and_ignores_unknown_routes() {
        let configured = strings(["webrtc", "iroh-lan"]);
        let candidates = strings([" IROH-LAN ", "unknown", "webrtc", "webrtc", "moq"]);
        assert_eq!(
            rank_routes(&configured, &candidates),
            strings(["webrtc", "iroh-lan", "moq"])
        );
    }

    #[test]
    fn empty_priority_preserves_the_public_default_order() {
        let candidates = strings([
            "iroh",
            "moq",
            "webrtc",
            "ble",
            "webrtc-lan",
            "iroh-lan",
            "iroh-quic",
            "iroh-relay",
            "webrtc-turn",
        ]);
        assert_eq!(
            rank_routes(&[], &candidates),
            strings([
                "iroh-lan",
                "webrtc-lan",
                "ble",
                "webrtc",
                "moq",
                "iroh",
                "iroh-quic",
                "iroh-relay",
                "webrtc-turn",
            ])
        );
    }

    #[test]
    fn vectors_are_shared_with_other_language_consumers() {
        let vectors: PolicyVectors =
            serde_json::from_str(crate::generated::route_registry::TRANSPORT_REGISTRY_JSON)
                .expect("transport policy vectors");
        for vector in vectors.rank_routes {
            assert_eq!(
                rank_routes(&vector.configured_priority, &vector.candidates),
                vector.expected,
                "configured={:?} candidates={:?}",
                vector.configured_priority,
                vector.candidates
            );
        }
    }

    fn strings<const N: usize>(values: [&str; N]) -> Vec<String> {
        values.into_iter().map(str::to_string).collect()
    }
}