pgaf 0.1.0

Parallel Geospatial Analysis Framework — Work-In-Progress lightweight tool for mass-parallel geospatial analysis.
use std::collections::HashMap;
use std::fmt;
use std::marker::PhantomData;
use std::path::PathBuf;

use pgaf_engine::context::value::ContextValueDeserializeSeed;
use pgaf_sdk::config::{Config, RunConfig, SiteSourceConfig};
use pgaf_sdk::context::ContextValue;
use pgaf_sdk::registry::{
    PublicIdentifierSeed, Registries, ResourceSeed, SiteGeneratorDriverResource,
};
use serde::de::{DeserializeSeed, MapAccess, SeqAccess, Visitor};
use serde_json::value::{Map, Value};

pub struct ConfigDeserializeSeed<'a, T = Config> {
    pub default_namespace: String,
    pub registries: &'a Registries,
    _marker: PhantomData<T>,
}

impl<'a, T> ConfigDeserializeSeed<'a, T> {
    fn cast<U>(self) -> ConfigDeserializeSeed<'a, U> {
        ConfigDeserializeSeed {
            default_namespace: self.default_namespace,
            registries: self.registries,
            _marker: PhantomData,
        }
    }
}

impl<'a, T> Clone for ConfigDeserializeSeed<'a, T> {
    fn clone(&self) -> Self {
        ConfigDeserializeSeed {
            default_namespace: self.default_namespace.clone(),
            registries: self.registries,
            _marker: PhantomData,
        }
    }
}

impl<'a> ConfigDeserializeSeed<'a, Config> {
    pub fn new(registries: &'a Registries, default_namespace: &str) -> Self {
        Self {
            default_namespace: default_namespace.to_string(),
            registries,
            _marker: PhantomData,
        }
    }
}

struct ConfigVisitor<'a, T> {
    seed: ConfigDeserializeSeed<'a, T>,
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, Config> {
    type Value = Config;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_map(ConfigVisitor { seed: self })
    }
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, SiteSourceConfig> {
    type Value = SiteSourceConfig;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_map(ConfigVisitor { seed: self })
    }
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, Vec<RunConfig>> {
    type Value = Vec<RunConfig>;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_seq(ConfigVisitor { seed: self })
    }
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, RunConfig> {
    type Value = RunConfig;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_map(ConfigVisitor { seed: self })
    }
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, SiteGeneratorDriverResource> {
    type Value = SiteGeneratorDriverResource;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        ResourceSeed {
            registry: self.registries.reg_sitegen_drivers(),
            id_seed: PublicIdentifierSeed {
                default_namespace: self.default_namespace,
            },
        }
        .deserialize(deserializer)
        .map(|r| r.resource)
    }
}

impl<'de> DeserializeSeed<'de> for ConfigDeserializeSeed<'de, ContextValue> {
    type Value = ContextValue;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        ContextValueDeserializeSeed {
            default_namespace: self.default_namespace,
            registries: self.registries,
        }
        .deserialize(deserializer)
    }
}

impl<'de> Visitor<'de> for ConfigVisitor<'de, Config> {
    type Value = Config;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a Config struct")
    }

    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    where
        A: MapAccess<'de>,
    {
        let mut sites: Option<SiteSourceConfig> = None;
        let mut runs = None;

        while let Some(key) = map.next_key::<String>()? {
            match key.as_str() {
                "sites" => {
                    sites = Some(map.next_value_seed(self.seed.clone().cast::<SiteSourceConfig>())?)
                }
                "runs" => {
                    runs = Some(map.next_value_seed(self.seed.clone().cast::<Vec<RunConfig>>())?)
                }
                _ => return Err(serde::de::Error::unknown_field(&key, &["sites", "runs"])),
            }
        }

        let sites = sites.ok_or_else(|| serde::de::Error::missing_field("sites"))?;
        let runs = runs.ok_or_else(|| serde::de::Error::missing_field("runs"))?;

        Ok(Config { sites, runs })
    }
}

impl<'de> Visitor<'de> for ConfigVisitor<'de, SiteSourceConfig> {
    type Value = SiteSourceConfig;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a SiteSourceConfig struct")
    }

    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    where
        A: MapAccess<'de>,
    {
        let mut resource: Option<SiteGeneratorDriverResource> = None;
        let mut sample_size = None;
        let mut args: Map<String, serde_json::Value> = Map::new();

        while let Some(key) = map.next_key::<String>()? {
            match key.as_str() {
                "type" => {
                    resource =
                        Some(map.next_value_seed(
                            self.seed.clone().cast::<SiteGeneratorDriverResource>(),
                        )?)
                }
                "sample_size" => sample_size = Some(map.next_value()?),
                _ => {
                    args.insert(key.to_string(), map.next_value()?);
                }
            }
        }

        let resource = resource.ok_or_else(|| serde::de::Error::missing_field("type"))?;
        Ok(SiteSourceConfig {
            driver: resource.0,
            sample_size,
            args: Value::Object(args),
        })
    }
}

impl<'de> Visitor<'de> for ConfigVisitor<'de, Vec<RunConfig>> {
    type Value = Vec<RunConfig>;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a sequence of RunConfig objects")
    }

    fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
    where
        S: SeqAccess<'de>,
    {
        let mut runs = Vec::with_capacity(seq.size_hint().unwrap_or(0));

        while let Some(run) = seq.next_element_seed(self.seed.clone().cast::<RunConfig>())? {
            runs.push(run);
        }

        Ok(runs)
    }
}

impl<'de> Visitor<'de> for ConfigVisitor<'de, RunConfig> {
    type Value = RunConfig;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a RunConfig object")
    }

    fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut name: Option<String> = None;
        let mut template: Option<PathBuf> = None;
        let mut extra = HashMap::new();

        while let Some(key) = map.next_key::<String>()? {
            match key.as_str() {
                "name" => {
                    if name.is_some() {
                        return Err(serde::de::Error::duplicate_field("name"));
                    }
                    name = Some(map.next_value()?);
                }
                "template" => {
                    if template.is_some() {
                        return Err(serde::de::Error::duplicate_field("template"));
                    }
                    template = Some(map.next_value()?);
                }
                _ => {
                    let value = map.next_value_seed(self.seed.clone().cast::<ContextValue>())?;
                    extra.insert(key, value);
                }
            }
        }

        let name = name.ok_or_else(|| serde::de::Error::missing_field("name"))?;
        let template = template.ok_or_else(|| serde::de::Error::missing_field("template"))?;

        Ok(RunConfig {
            name,
            template,
            extra,
        })
    }
}