d3ne 0.7.0

Rust D3 Node Engine implementation that works with retejs, still a work in progress
Documentation
use std::ops::Deref;
use std::rc::Rc;
use std::any::{Any, TypeId};
use serde::{Deserialize, Serialize};
use serde_json::{Value, Number};
use thiserror::Error;
use crate::target::{Inputs, Outputs};
use std::collections::HashMap;
use anyhow::Result;

#[derive(Debug)]
pub struct IOData {
  pub data: Box<dyn Any>
}

#[allow(dead_code)]
impl IOData {
  pub fn is<B: Any>(&self) -> bool {
    return TypeId::of::<B>() == (*self.data).type_id()
  }
  pub fn get<A>(&self) -> Option<&A> where A: 'static {
    return self.data.downcast_ref::<A>();
  }
}

#[derive(Debug, Error)]
pub enum NodeError {
  #[error("Node input conversion error: {0}")]
  ConversionError(String),
  #[error("No value found for: {0}")]
  NoValueFound(String),
  #[error("Field: {0}, Value: {1}, Deserialization error: {2}")]
  DeserializeError(String, String, serde_json::Error)
}


#[derive(Debug)]
pub struct NodeResult(pub IOData);

impl Deref for NodeResult {
    type Target = IOData;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct OutputData(pub Rc<HashMap<String, NodeResult>>);

impl From<Rc<HashMap<String, NodeResult>>> for OutputData {
    fn from(inner: Rc<HashMap<String, NodeResult>>) -> Self {
        OutputData(inner)
    }
}

pub struct OutputDataBuilder<'a> {
  data: Vec<(&'a str, Box<dyn Any>)>
}

impl <'a> OutputDataBuilder<'a> {
  pub fn new() -> OutputDataBuilder<'a> {
    OutputDataBuilder { data: vec![] }
  }

  pub fn add_data(&mut self, key: &'a str, data: Box<dyn Any>) -> &mut Self {
    self.data.push((key, data));
    self
  }

  pub fn data(mut self, key: &'a str, data: Box<dyn Any>) -> Self {
    self.data.push((key, data));
    self
  }

  pub fn build(self) -> OutputData {
    OutputData(Rc::new(self.data.into_iter().map(|(key, data)| (key.into(), NodeResult(IOData { data }))).collect::<HashMap<_,_>>() ))
  }

}

impl Deref for OutputData {
    type Target = Rc<HashMap<String, NodeResult>>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[allow(dead_code)]
#[derive(Debug)]
pub struct InputData(pub HashMap<String, OutputData>);

pub struct InputDataBuilder {
  data: Vec<(String, OutputData)>
}

impl InputDataBuilder {
  pub fn new() -> InputDataBuilder {
    InputDataBuilder { data: vec![] }
  }

  pub fn add_data(mut self, key: String, data: OutputData) -> InputDataBuilder {
    self.data.push((key, data));
    self
  }

  pub fn build(self) -> InputData {
    InputData(self.data.into_iter().map(|(key, data)| (key.into(), data)).collect::<HashMap<_,_>>())
  }
}

impl From<HashMap<String, OutputData>> for InputData {
    fn from(inner: HashMap<String, OutputData>) -> Self {
        InputData(inner)
    }
}

impl Deref for InputData {
  type Target = HashMap<String, OutputData>;
  fn deref(&self) -> &Self::Target {
      &self.0
  }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Node {
  pub id: i64,
  pub name: String,
  pub data: Option<Value>,
  pub group: Option<i64>,
  pub position: Option<Vec<f32>>,
  pub inputs: Option<Inputs>,
  pub outputs: Option<Outputs>
}

impl Node {
  fn get_field<A>(&self, field: &'static str, inputs: &InputData, def: A, deref: Box<dyn Fn(&A) -> A>, convert: Box<dyn Fn(&Value) -> Result<A>>, noerr: Option<A> ) -> Result<A> where A: 'static {
    inputs.0.get(field)
      .and_then(|i| i.get(&self.inputs.clone().map(|i| i[field].connections[0].output.clone()).unwrap_or_default()))
      .map(|v| Ok(v.get::<A>().map(deref).unwrap_or(def)))
      .or(self.data.clone().and_then(|d| d.get(field).map(|v| convert(v))))
      .or(noerr.map(Ok)).unwrap_or(
        Err(anyhow!("{}", NodeError::NoValueFound(field.into())))
      )
  }
  
  pub fn get_number_field_or(&self, field: &'static str, inputs: &InputData, default: Option<i64>) -> Result<i64> {
    self.get_field(
      field,
      inputs,
      i64::MIN,
      Box::new(|r| *r),
      Box::new(|v| v.as_i64().ok_or(anyhow!(NodeError::ConversionError(format!("Field: {}, Type: {}", field.to_string(), std::any::type_name::<i64>()))))),
      default
    )
  }
  
  pub fn get_float_number_field_or(&self, field: &'static str, inputs: &InputData, default: Option<f64>) -> Result<f64> {
    self.get_field(
      field,
      inputs,
      f64::MIN,
      Box::new(|r| *r),
      Box::new(|v| v.as_f64().ok_or(anyhow!(NodeError::ConversionError(format!("Field: {}, Type: {}", field.to_string(), std::any::type_name::<f64>()))))),
      default
    )
  }

  pub fn get_string_field_or(&self, field: &'static str, inputs: &InputData, default: Option<String>) -> Result<String> {
    self.get_field(
      field,
      inputs,
      String::default(),
      Box::new(|r| r.to_owned()),
      Box::new(|v| {
        if let Value::String(s) = v { 
          Ok(s.clone()) 
        } else {
          Err(anyhow!(NodeError::ConversionError(format!("Field: {}, Type: {}", field.to_string(), std::any::type_name::<String>()))))
        }
      }),
      default
    )
  }

  pub fn get_json_field_or(&self, field: &'static str, inputs: &InputData, default: Option<Value>) -> Result<Value> {
    self.get_field(
      field,
      inputs,
      json!({}),
      Box::new(|r| r.clone()),
      Box::new(|v| { 
        serde_json::from_str(v.as_str().ok_or(anyhow!("Field: {}, unable to get str value for deserialze", field.to_string()))?)
          .map_err(|e| anyhow!(NodeError::DeserializeError(field.to_string(), format!("[{:?}]json({})", TypeId::of::<Value>(), v.as_str().unwrap_or_default().to_string()), e)))
      }),
      default)
  }

  pub fn get_as_json_field_or(&self, field: &'static str, inputs: &InputData, default: Option<Value>) -> Result<Value> {
    let err = format!("Field: {}, No josn, bool, i64, f64 or String value found", field.to_string());
    inputs.get(field)
      .and_then(|i| i.get(&self.inputs.clone().map(|i| i[field].connections[0].output.clone()).unwrap_or_default()).map(|r| {
        let NodeResult(v) = r;
        if v.is::<Value>() {
          v.get::<Value>().map(|v| v.clone()).ok_or(anyhow!(NodeError::ConversionError("Unable to get `Value` as json field".to_owned())))
        } else if v.is::<bool>() {
          v.get::<bool>().map(|b| Value::Bool(*b)).ok_or(anyhow!(NodeError::ConversionError("Unable to get `bool` as json field".to_owned())))
        } else if v.is::<i64>() {
          v.get::<i64>().map(|i| Number::from(*i)).map(Value::Number).ok_or(anyhow!(NodeError::ConversionError("Unable to get `i64` as json field".to_owned())))
        } else if v.is::<f64>() {
          v.get::<f64>().and_then(|f| Number::from_f64(*f)).map(Value::Number).ok_or(anyhow!(NodeError::ConversionError("Unable to get `i64` as json field".to_owned())))
        } else if v.is::<String>() {
          v.get::<String>().map(|v| Value::String(v.clone())).ok_or(anyhow!(NodeError::ConversionError("Unable to get `String` as json field".to_owned())))
        } else {
          default.clone().ok_or(anyhow!(err.to_owned()))
        }
      }))
      .or(self.data.clone().and_then(|d| d.get(field).map(|v| Ok(v.clone()))))
      .or(default.map(Ok))
      .unwrap_or(Err(anyhow!(err.to_owned())))

  }

  pub fn get_as_json_field(&self, field: &'static str, inputs: &InputData) -> Result<Value> {
    self.get_as_json_field_or(field, inputs, None)
  }

  pub fn get_string_field(&self, field: &'static str, inputs: &InputData) -> Result<String> {
    self.get_string_field_or(field, inputs, None)
  }
  
  pub fn get_number_field(&self, field: &'static str, inputs: &InputData) -> Result<i64> {
    self.get_number_field_or(field, inputs, None)
  }
  
  pub fn get_float_number_field(&self, field: &'static str, inputs: &InputData) -> Result<f64> {
    self.get_float_number_field_or(field, inputs, None)
  }
  
  pub fn get_json_field(&self, field: &'static str, inputs: &InputData) -> Result<Value> {
    self.get_json_field_or(field, inputs, None)
  }
}