omg_serde 0.1.0

Adds serde support to omg_core.
Documentation
use crate::data::math::interpolation::vector::EntrySerde;
use anyhow::Result;
use omg_core::data::color::Color;
use omg_core::data::math::selector::ColorSelector;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
pub enum ColorSelectorSerde {
    Const(String),
    InterpolatePair {
        first: String,
        second: String,
    },
    InterpolateVector(Vec<EntrySerde<u8, String>>),
    Lookup {
        lookup: HashMap<u8, String>,
        default: String,
    },
}

type S = ColorSelectorSerde;
type R = ColorSelector;

impl ColorSelectorSerde {
    pub fn try_convert(self) -> Result<ColorSelector> {
        match self {
            S::Const(value) => {
                let color = Color::try_from(value)?;
                Ok(R::Const(color))
            }
            S::InterpolatePair { first, second } => {
                let first = Color::try_from(first)?;
                let second = Color::try_from(second)?;
                Ok(R::new_interpolate_pair(first, second))
            }
            S::InterpolateVector(interpolate) => {
                let vector: Result<Vec<(u8, Color)>> = interpolate
                    .into_iter()
                    .map(|e| e.value().clone().try_into().map(|c| (e.threshold(), c)))
                    .collect();
                Ok(R::new_interpolate_vector(vector?)?)
            }
            S::Lookup { lookup, default } => {
                let result: Result<Vec<(u8, Color)>> = lookup
                    .into_iter()
                    .map(|(input, value)| value.try_into().map(|c| (input, c)))
                    .collect();
                Ok(R::new_lookup(
                    result?.into_iter().collect(),
                    default.try_into()?,
                ))
            }
        }
    }
}

impl From<&ColorSelector> for ColorSelectorSerde {
    fn from(interpolator: &ColorSelector) -> Self {
        match interpolator {
            R::Const(value) => S::Const((*value).into()),
            R::InterpolatePair { first, second } => S::InterpolatePair {
                first: (*first).into(),
                second: (*second).into(),
            },
            R::InterpolateVector(interpolate) => {
                let vector: Vec<EntrySerde<u8, String>> = interpolate
                    .get_all()
                    .iter()
                    .map(|e| EntrySerde::new(e.threshold(), String::from(e.value())))
                    .collect();
                S::InterpolateVector(vector)
            }
            R::Lookup { lookup, default } => {
                let lookup = lookup
                    .iter()
                    .map(|(input, value)| (*input, (*value).into()))
                    .collect();
                S::Lookup {
                    lookup,
                    default: (*default).into(),
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use omg_core::data::color::{BLUE, RED};

    #[test]
    fn test_conversion() {
        let start = ColorSelector::Const(RED);
        let serde: ColorSelectorSerde = (&start).into();

        assert_eq!(serde.try_convert().unwrap(), start)
    }

    #[test]
    fn test_convert_color_selector() {
        let vector = vec![(0u8, RED), (200u8, BLUE)];
        let start = ColorSelector::new_interpolate_vector(vector).unwrap();
        let serde: ColorSelectorSerde = (&start).into();

        assert_eq!(serde.try_convert().unwrap(), start)
    }
}