node_editor 0.0.3

Node editor UI using imgui-rs as backend, made for aflak project
Documentation
use std::collections::BTreeMap;
use std::fs;
use std::io;
use std::path::Path;

use cake::{self, DeserDST, NamedAlgorithms, NodeId, SerialDST, Transformation, VariantName};
use ron::{de, ser};
use serde::{Deserialize, Serialize};

use compute;
use editor::NodeEditor;
use node_state::{NodeState, NodeStates};
use scrolling::Scrolling;
use vec2::Vec2;

#[derive(Serialize)]
pub struct SerialEditor<'e, T: 'e> {
    dst: SerialDST<'e, T>,
    node_states: Vec<(&'e NodeId, &'e NodeState)>,
    scrolling: Vec2,
}

impl<'e, T> SerialEditor<'e, T>
where
    T: Clone,
{
    fn new<E, ED>(editor: &'e NodeEditor<T, E, ED>) -> Self {
        Self {
            dst: SerialDST::new(&editor.dst),
            node_states: editor.node_states.iter().collect(),
            scrolling: editor.scrolling.get_current(),
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
#[serde(bound(deserialize = "T: Deserialize<'de>"))]
pub struct DeserEditor<T, E> {
    dst: DeserDST<T, E>,
    node_states: Vec<(NodeId, NodeState)>,
    scrolling: Vec2,
}

impl<'t, T, E, ED> NodeEditor<'t, T, E, ED>
where
    T: Clone,
{
    pub fn export(&self) -> SerialEditor<T> {
        SerialEditor::new(self)
    }
}

#[derive(Debug)]
pub enum ExportError {
    SerializationError(ser::Error),
    IOError(io::Error),
}

impl From<io::Error> for ExportError {
    fn from(io_error: io::Error) -> Self {
        ExportError::IOError(io_error)
    }
}

impl From<ser::Error> for ExportError {
    fn from(serial_error: ser::Error) -> Self {
        ExportError::SerializationError(serial_error)
    }
}

impl<'t, T, E, ED> NodeEditor<'t, T, E, ED>
where
    T: Clone + Serialize,
{
    pub fn export_to_buf<W: io::Write>(&self, w: &mut W) -> Result<(), ExportError> {
        let serializable = self.export();
        let serialized = ser::to_string_pretty(&serializable, Default::default())?;
        w.write(serialized.as_bytes())?;
        Ok(w.flush()?)
    }

    pub fn export_to_file<P: AsRef<Path>>(&self, file_path: P) -> Result<(), ExportError> {
        let mut f = fs::File::create(file_path)?;
        self.export_to_buf(&mut f)
    }
}

impl<'t, T, E, ED> NodeEditor<'t, T, E, ED>
where
    T: 'static + Clone + NamedAlgorithms<E> + VariantName,
    E: 'static,
{
    pub fn import(&mut self, import: DeserEditor<T, E>) -> Result<(), cake::ImportError<E>> {
        // Replace DST. Wait for no computing to take place.
        use std::{thread, time};
        const SLEEP_INTERVAL_MS: u64 = 1;
        let sleep_interval = time::Duration::from_millis(SLEEP_INTERVAL_MS);
        println!("Import requested! Wait for pending compute tasks to complete...");
        let now = time::Instant::now();
        loop {
            if !self.is_compute_running() {
                println!("Starting import after {:?}", now.elapsed());
                break;
            } else {
                thread::sleep(sleep_interval);
            }
        }
        self.dst = import.dst.into()?;

        // Set Ui node states
        self.node_states = {
            let mut node_states = NodeStates::new();
            for (node_id, state) in import.node_states {
                node_states.insert(node_id, state);
            }
            node_states
        };
        // Set scrolling offset
        self.scrolling = Scrolling::new(import.scrolling);

        // Reset cache
        self.output_results = {
            let mut output_results = BTreeMap::new();
            for (output_id, _) in self.dst.outputs_iter() {
                output_results.insert(*output_id, compute::new_compute_result());
            }
            output_results
        };
        Ok(())
    }
}

#[derive(Debug)]
pub enum ImportError<E> {
    DSTError(cake::ImportError<E>),
    DeserializationError(de::Error),
    IOError(io::Error),
}

impl<E> From<io::Error> for ImportError<E> {
    fn from(io_error: io::Error) -> Self {
        ImportError::IOError(io_error)
    }
}

impl<E> From<de::Error> for ImportError<E> {
    fn from(deserial_error: de::Error) -> Self {
        ImportError::DeserializationError(deserial_error)
    }
}

impl<E> From<cake::ImportError<E>> for ImportError<E> {
    fn from(e: cake::ImportError<E>) -> Self {
        ImportError::DSTError(e)
    }
}

impl<'t, T, E, ED> NodeEditor<'t, T, E, ED>
where
    T: 'static + Clone + NamedAlgorithms<E> + VariantName + for<'de> Deserialize<'de>,
    E: 'static,
    ED: Default,
{
    pub fn from_export_buf<R>(
        r: R,
        addable_nodes: &'t [&'t Transformation<T, E>],
        ed: ED,
    ) -> Result<Self, ImportError<E>>
    where
        R: io::Read,
    {
        let mut editor = Self::new(addable_nodes, ed);
        editor.import_from_buf(r)?;
        Ok(editor)
    }

    pub fn from_ron_file<P>(
        file_path: P,
        addable_nodes: &'t [&'t Transformation<T, E>],
        ed: ED,
    ) -> Result<Self, ImportError<E>>
    where
        P: AsRef<Path>,
    {
        let f = fs::File::open(file_path)?;
        Self::from_export_buf(f, addable_nodes, ed)
    }

    pub fn import_from_buf<R: io::Read>(&mut self, r: R) -> Result<(), ImportError<E>> {
        let deserialized = de::from_reader(r)?;
        Ok(self.import(deserialized)?)
    }

    pub fn import_from_file<P: AsRef<Path>>(&mut self, file_path: P) -> Result<(), ImportError<E>> {
        let f = fs::File::open(file_path)?;
        self.import_from_buf(f)
    }
}