flow-graph-interpreter 0.22.0

An intepreter for flow-based programs
Documentation
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

pub(crate) mod component;
pub(crate) mod core;
pub(crate) mod internal;
pub(crate) mod null;
pub(crate) mod self_component;

use flow_component::Component;
use wick_interface_types::{ComponentSignature, OperationSignature};

use self::core::CoreComponent;
use self::internal::InternalComponent;
use crate::error::InterpreterError;
use crate::graph::types::Network;
use crate::SharedHandler;

pub(crate) type ComponentMap = HashMap<String, ComponentSignature>;

#[derive(Debug)]
#[must_use]
pub struct HandlerMap {
  components: HashMap<String, NamespaceHandler>,
}

impl Default for HandlerMap {
  fn default() -> Self {
    Self::new(Vec::new()).unwrap()
  }
}

impl HandlerMap {
  pub fn new(components: Vec<NamespaceHandler>) -> Result<Self, InterpreterError> {
    let mut map = Self {
      components: Default::default(),
    };
    for component in components {
      map.add(component)?;
    }

    map.add(NamespaceHandler::new(
      InternalComponent::ID,
      Box::new(InternalComponent::default()),
    ))?;

    Ok(map)
  }

  pub(crate) fn add_core(&mut self, network: &Network) -> Result<(), InterpreterError> {
    self.add(NamespaceHandler::new(
      CoreComponent::ID,
      Box::new(CoreComponent::new(network, self)?),
    ))
  }

  #[must_use]
  pub const fn inner(&self) -> &HashMap<String, NamespaceHandler> {
    &self.components
  }

  #[must_use]
  pub fn component_signatures(&self) -> ComponentMap {
    self
      .components
      .iter()
      .map(|(name, p)| (name.clone(), p.component.signature().clone()))
      .collect::<HashMap<String, ComponentSignature>>()
  }

  #[must_use]
  pub fn get(&self, namespace: &str) -> Option<&NamespaceHandler> {
    self.components.get(namespace)
  }

  #[must_use]
  pub fn has(&self, namespace: &str) -> bool {
    self.components.contains_key(namespace)
  }

  pub fn add(&mut self, component: NamespaceHandler) -> Result<(), InterpreterError> {
    if self.components.contains_key(&component.namespace) {
      return Err(InterpreterError::DuplicateNamespace(component.namespace));
    }
    self.components.insert(component.namespace.clone(), component);
    Ok(())
  }

  pub(crate) fn keys(&self) -> Vec<String> {
    self.components.keys().cloned().collect()
  }

  #[allow(unused)]
  pub(crate) fn get_signature(&self, namespace: &str) -> Option<&ComponentSignature> {
    self.components.get(namespace).map(|c| c.component.signature())
  }

  pub(crate) fn get_op_signature(&self, namespace: &str, name: &str) -> Option<&OperationSignature> {
    self
      .components
      .get(namespace)
      .and_then(|c| c.component.signature().get_operation(name))
  }

  pub(crate) fn get_op_list(&self, namespace: &str) -> Vec<&str> {
    self
      .components
      .get(namespace)
      .map(|c| {
        c.component
          .signature()
          .operations
          .iter()
          .map(|op| op.name.as_str())
          .collect::<Vec<_>>()
      })
      .unwrap_or_default()
  }
}

pub(crate) fn dyn_component_id(name: &str, schematic: &str, instance: &str) -> String {
  format!("{}<{}::{}>", name, schematic, instance)
}

pub(crate) fn reconcile_op_id(ns: &str, name: &str, schematic: &str, instance: &str) -> String {
  if ns == CoreComponent::ID && core::DYNAMIC_OPERATIONS.contains(&name) {
    dyn_component_id(name, schematic, instance)
  } else {
    name.to_owned()
  }
}

#[derive(Clone)]
#[must_use]
pub struct NamespaceHandler {
  pub(crate) namespace: String,
  pub(crate) component: SharedHandler,
  pub(crate) exposed: Arc<AtomicBool>,
}

impl NamespaceHandler {
  pub fn new<T: Into<String>>(namespace: T, component: Box<dyn Component + Send + Sync>) -> Self {
    Self {
      namespace: namespace.into(),
      component: Arc::new(component),
      exposed: Arc::new(AtomicBool::new(false)),
    }
  }

  pub fn new_from_shared<T: Into<String>>(namespace: T, component: Arc<Box<dyn Component + Send + Sync>>) -> Self {
    Self {
      namespace: namespace.into(),
      component,
      exposed: Arc::new(AtomicBool::new(false)),
    }
  }

  #[must_use]
  pub fn namespace(&self) -> &str {
    &self.namespace
  }

  #[must_use]
  pub fn component(&self) -> &SharedHandler {
    &self.component
  }

  pub fn expose(&self) {
    self.exposed.store(true, std::sync::atomic::Ordering::Relaxed);
  }

  #[must_use]
  pub fn is_exposed(&self) -> bool {
    self.exposed.load(std::sync::atomic::Ordering::Relaxed)
  }
}

impl Debug for NamespaceHandler {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("NamespaceHandler")
      .field("namespace", &self.namespace)
      .field("component", &self.component.signature())
      .finish()
  }
}