sim-lib-server 0.1.0-rc.1

SIM workspace package for sim lib server.
Documentation
use sim_kernel::{Cx, Error, Result, Symbol};

pub(crate) fn installed_server_codecs(cx: &Cx) -> Vec<Symbol> {
    cx.registry().codecs().keys().cloned().collect()
}

pub(crate) fn default_server_codec(codecs: &[Symbol]) -> Result<Symbol> {
    codecs
        .iter()
        .find(|symbol| **symbol == Symbol::qualified("codec", "lisp"))
        .cloned()
        .or_else(|| codecs.first().cloned())
        .ok_or_else(|| Error::Eval("server/start: no installed codecs available".to_owned()))
}

pub(crate) fn ensure_installed_codec(cx: &Cx, codec: &Symbol) -> Result<()> {
    if cx.registry().codec_by_symbol(codec).is_some() {
        Ok(())
    } else {
        Err(Error::Eval(format!("server/start: unknown codec {codec}")))
    }
}

pub(crate) fn normalize_codec_expr(cx: &Cx, symbol: &Symbol) -> Option<Symbol> {
    if cx.registry().codec_by_symbol(symbol).is_some() {
        return Some(symbol.clone());
    }
    let qualified = Symbol::qualified("codec", symbol.name.to_string());
    cx.registry().codec_by_symbol(&qualified).map(|_| qualified)
}

pub(crate) fn default_connection_codec(codecs: &[Symbol]) -> Result<Symbol> {
    [
        Symbol::qualified("codec", "json"),
        Symbol::qualified("codec", "binary"),
        Symbol::qualified("codec", "lisp"),
    ]
    .into_iter()
    .find(|symbol| codecs.iter().any(|codec| codec == symbol))
    .or_else(|| codecs.first().cloned())
    .ok_or_else(|| Error::Eval("server/connect: no installed codecs available".to_owned()))
}

pub(crate) fn negotiation_offer_codecs(codecs: &[Symbol]) -> Vec<Symbol> {
    let preferred = [
        Symbol::qualified("codec", "binary"),
        Symbol::qualified("codec", "lisp"),
        Symbol::qualified("codec", "json"),
    ];
    let mut ordered = Vec::new();
    for symbol in preferred {
        if codecs.iter().any(|codec| codec == &symbol) {
            ordered.push(symbol);
        }
    }
    for codec in codecs {
        if !ordered.iter().any(|existing| existing == codec) {
            ordered.push(codec.clone());
        }
    }
    ordered
}

pub(crate) fn choose_codec(
    default_codec: Symbol,
    supported_codecs: &[Symbol],
    explicit: Option<Symbol>,
    preferred: &[Symbol],
) -> Result<Symbol> {
    if let Some(codec) = explicit {
        if supported_codecs.iter().any(|candidate| candidate == &codec) {
            return Ok(codec);
        }
        return Err(Error::Eval(format!(
            "connection target does not support codec {codec}"
        )));
    }
    if let Some(codec) = preferred
        .iter()
        .find(|codec| supported_codecs.iter().any(|candidate| candidate == *codec))
    {
        return Ok(codec.clone());
    }
    Ok(default_codec)
}