ph-haptics 0.1.0

Host-compiled haptics DSL and no-std, no-alloc scheduling runtime modeling ERM and LRA motors using ph-curves
Documentation
use crate::ident::to_const_ident;
use crate::model::{CurveRef, Haptic, Motor, Profile};
use std::collections::BTreeMap;

pub(crate) fn profile_map(profiles: &[Profile]) -> BTreeMap<&str, &Profile> {
    let mut map = BTreeMap::new();
    for profile in profiles {
        map.insert(profile.name.as_str(), profile);
    }
    map
}

pub(crate) fn profile_for_haptic<'a>(
    haptic: &Haptic,
    profile_map: &BTreeMap<&'a str, &'a Profile>,
    default_erm: &'a Profile,
    default_lra: &'a Profile,
) -> Result<Option<&'a Profile>, String> {
    match &haptic.profile {
        Some(name) => profile_map
            .get(name.as_str())
            .copied()
            .map(Some)
            .ok_or(format!("line {}: unknown profile `{name}`", haptic.line)),
        None if haptic.motor == Motor::Erm => Ok(Some(default_erm)),
        None => Ok(Some(default_lra)),
    }
}

pub(crate) fn resolve_curve_symbol(
    curve: &CurveRef,
    profile: Option<&Profile>,
    line: u32,
    haptic_name: &str,
) -> Result<String, String> {
    match curve {
        CurveRef::Named(name) => Ok(curve_symbol(name)),
        CurveRef::Gamma => {
            let profile = profile.ok_or(format!(
                "line {line}: `@gamma` requires profile on `{haptic_name}`"
            ))?;
            let gamma = profile.gamma.as_ref().ok_or(format!(
                "line {line}: profile `{}` does not define gamma",
                profile.name
            ))?;
            Ok(curve_symbol(gamma))
        }
    }
}

fn curve_symbol(name: &str) -> String {
    to_const_ident(name)
}