reefast 0.0.1

Rust Engine for Eve Fit Analysis, Statistics and Theorycrafting.
Documentation
use crate::defines::ReeInt;
use crate::dh;

use super::error::{Error, Result};

pub(super) trait FsdMerge<T> {
    fn fsd_merge(self, id: ReeInt) -> Vec<T>;
}

#[derive(Debug)]
pub(super) struct FsdItem {
    pub(super) id: String,
    pub(super) item: serde_json::Value,
}
impl FsdItem {
    pub(super) fn new<T: Into<String>>(id: T, item: serde_json::Value) -> FsdItem {
        FsdItem { id: id.into(), item }
    }
}

pub(super) fn handle<T, U>(unprocessed: serde_json::Value) -> dh::Result<dh::Container<U>>
where
    T: serde::de::DeserializeOwned + FsdMerge<U>,
{
    let decomposed = decompose(unprocessed)?;
    convert::<T, U>(decomposed)
}

fn decompose(json: serde_json::Value) -> Result<Vec<FsdItem>> {
    match json {
        serde_json::Value::Object(map) => Ok(map.into_iter().map(|(k, v)| FsdItem::new(k, v)).collect()),
        _ => Err(Error::new(
            "FSD decomposition failed: highest-level entity is not a map",
        )),
    }
}

fn convert<T, U>(decomposed: Vec<FsdItem>) -> dh::Result<dh::Container<U>>
where
    T: serde::de::DeserializeOwned + FsdMerge<U>,
{
    let mut data = Vec::new();
    let mut errors = Vec::new();
    for fsd_item in decomposed {
        match fsd_item.id.parse::<ReeInt>() {
            Ok(id) => match serde_json::from_value::<T>(fsd_item.item) {
                Ok(item) => data.extend(item.fsd_merge(id)),
                Err(e) => errors.push(format!("failed to parse FSD item with key \"{}\": {}", id, e)),
            },
            Err(_) => errors.push(format!("failed to cast FSD key \"{}\" to integer", fsd_item.id)),
        }
    }
    Ok(dh::Container::new(data, errors))
}