cellular_lib 0.1.1

A library for simulation of cellular automata
Documentation
#![allow(dead_code)]

use super::util;
use std::cell::Cell;
use std::fmt::Debug;
use std::str::FromStr;
/*
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
*/

/// Trait `GridMeta` is the trait that all metadata for a Grid must satisfy
pub trait GridMeta {
    fn get_dimensions(&self) -> &[usize];
}

/// `GridDataType` is the datatype of the data inside of a grid (the struct Grid is just a wrapper around `GridDataType` with a few more functions)
#[derive(Default, Clone, Debug)]
pub struct GridDataType<CellDataType: Clone + util::Encodeable> {
    /// Data is just the data of the grid. The data is "flattened" to 1 dimension, no matter how many dimensions the grid is
    pub data: Vec<util::NanoVec<CellDataType>>,
    /// Dimensions is a pointer to the dimensions_vec
    pub dimensions: Vec<usize>,
}

#[derive(Clone)]
/// `NeighborType` is the datatype for the neighborhood of a cell
pub struct NeighborType<'a, CellDataType: Clone + util::Encodeable> {
    /// Data contains the neighborhood
    pub data: Vec<&'a util::NanoVec<CellDataType>>,
    /// Dimensions is the dimensions
    pub dimensions: &'a [usize],
}

/// `TransitionFunc` is the transition function (AKA "rule") of the cellular automata
pub type TransitionFunc<CellDataType, MetaDataType /*: util::Newable*/> =
    dyn Fn(&mut util::NanoVec<CellDataType>, &NeighborType<CellDataType>, &MetaDataType) -> ();

/// `NeighborFuncParser` is the function that returns the neighborhood of a cell
pub type NeighborFuncParser<CellDataType, MetaDataType /*: util::Newable*/> =
    dyn for<'a> Fn(
        &'a GridDataType<CellDataType>,
        &'a MetaDataType,
        usize,
    ) -> NeighborType<'a, CellDataType>;

/// `HaltFunc` is the function that tells the program whether to halt or not (true = halt, false = not halt, obviously)
pub type HaltFunc<CellType> = Fn(&GridDataType<CellType>) -> bool;

/// Grid is the datatype for a Grid object, where all of the cells are stored
#[derive(Debug)]
pub struct Grid<
    CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable + Debug,
    MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
> {
    /// Direction determines which data (data_a or data_b) will be read from, and which data will be written to (the data being read from is never the data being written to). Direction "flops" each cycle. True = write to (modify) data_a, read from data_b (so data_a is ALWAYS the most recent one), false = other way around.
    direction: Cell<bool>,
    /// Data_a contains the vector. Depending on direction, it is either read to or written to.
    data_a: GridDataType<CellDataType>,
    /// Data_a contains the vector. Depending on direction, it is either read to or written to.
    data_b: GridDataType<CellDataType>,
    /// Metadata is the metadata for the grid (for example, for a grid with a modular cell type (e.g. all integers less than 5), the modulus would be metadata)
    meta: MetaDataType,
    /// Dimensions is a vector that stores the dimensions of the data - for example, a 2x2 grid (a 2d grid, with 2 rows and 2 columns) would be [2, 2]. The convention is that the size of x is before the size of y before the size of z etc, so a 3d grid with length (x size) 3, width (y size) 4 and height (z size) 5 would be [3,4,5]
    pub dimensions: Vec<usize>,
}

impl<
        CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable + Debug,
        MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
    > Default for Grid<CellDataType, MetaDataType>
{
    fn default() -> Self {
        Self::new()
    }
}

impl<
        CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable + Debug,
        MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
    > Grid<CellDataType, MetaDataType>
{
    /// Function new creates a blank Grid
    pub fn new() -> Self {
        let temp_grid_data: GridDataType<CellDataType> = GridDataType {
            data: Vec::new(),
            dimensions: Vec::new(),
        };
        Self {
            data_a: temp_grid_data.clone(),
            data_b: temp_grid_data.clone(),
            direction: Cell::new(true),
            meta: util::Newable::new(),
            dimensions: Vec::new(),
        }
    }
    /// Function get_data_read gets the old data from the struct
    pub fn get_data_read(&self) -> &GridDataType<CellDataType> {
        if self.direction.get() {
            &self.data_a
        } else {
            &self.data_b
        }
    }
    /// Function get_data_mut gets the newest data from the struct
    pub fn get_data_mut(&mut self) -> &mut GridDataType<CellDataType> {
        if self.direction.get() {
            &mut self.data_b
        } else {
            &mut self.data_a
        }
    }
    /// Function get_data_tuple gets the tuple of the data
    pub fn get_data_tuple(
        &mut self,
    ) -> (&mut GridDataType<CellDataType>, &GridDataType<CellDataType>) {
        if self.direction.get() {
            (&mut self.data_b, &self.data_a)
        } else {
            (&mut self.data_a, &self.data_b)
        }
    }
    /// Function get_meta gets the MetaData
    pub fn get_meta(&self) -> &MetaDataType {
        &self.meta
    }
    /// Function read_from_string reads a Grid from a string - mutating the object
    pub fn read_from_str(&mut self, data: &str) {
        *self = Self::decode(data);
    }
    /// Function decode decodes the data into a Grid type.
    pub fn decode(input: &str) -> Self {
        let split: Vec<String> = util::parse_table_sections(input); // Tokenize by semicolons, which seperates the data from the "metadata" - the "metadata" are things like the dimensions, and the "data" is the actual cell state
        if split.len() != 2 {
            // as of now, there are 2 "big tokens" (seperated by semicolons) - the first is the metadata (information about the rules, for example) and the second is the data.
            println!("ERROR - malformed input file.");
            panic!("ERROR - malformed input file.");
        }
        let meta_data_str: &str = &split[0];
        let meta_data: MetaDataType = util::Parseable::parse(meta_data_str);

        let dimensions_vec = meta_data.get_dimensions().to_vec();

        //let split_data: Vec<&str> = split[1].split(',').collect(); // Same as previous, but this time for the actual data, not the dimensions
        let data: Vec<util::NanoVec<CellDataType>> = {
            let tmp = util::split_str(&split[1], ';');
            let mut to_return: Vec<util::NanoVec<CellDataType>> = Vec::new();
            for item in tmp {
                let split = util::parse_csv_list(item, ',');
                to_return.push(util::NanoVec::from_slice(split.as_slice()));
            }
            to_return
        };
        //let mut data: Vec<CellDataType> = Vec::new();
        //for j in split_data {
        //    data.push(util::Parseable::parse(&String::from(j)[..]));
        //}
        let generated_data: GridDataType<CellDataType> =
            GridDataType::from_data(&data, &dimensions_vec);
        Self {
            data_a: generated_data.clone(),
            data_b: generated_data.clone(),
            direction: Cell::new(false),
            meta: meta_data,
            dimensions: dimensions_vec,
        }
    }
    /// Function apply performs one iteration
    #[inline]
    pub fn apply(
        &mut self,
        transition: &TransitionFunc<CellDataType, MetaDataType>,
        neighbor_parser: &NeighborFuncParser<CellDataType, MetaDataType>,
        meta: &MetaDataType,
    ) {
        let (active_data, to_read) = self.get_data_tuple();
        let to_modify_data = active_data.get_data_mut_ref();
        for (j, item) in to_modify_data.iter_mut().enumerate() {
            transition(item, &neighbor_parser(to_read, meta, j), meta);
        }
        self.direction.set(!self.direction.get());
    }
}

/// `ParseGridError` is a unit struct that signals a grid parsing error
pub struct ParseGridError {}

impl<
        CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable + Debug,
        MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
    > FromStr for Grid<CellDataType, MetaDataType>
{
    type Err = ParseGridError;
    /// Function from_str parses a Grid from a string. Does not mutate the object.
    fn from_str(data: &str) -> Result<Self, Self::Err> {
        let mut temp = Self::new();
        temp.read_from_str(data);
        Ok(temp)
    }
}

impl<CellDataType: Clone + util::Encodeable> std::fmt::Display for GridDataType<CellDataType> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let dimensions = &self.dimensions;
        if dimensions.len() == 2 {
            let mut the_str = String::new();
            let mut old_len = self.data.len();
            let sizes = dimensions
                .iter()
                .map(|&x| {
                    old_len /= x;
                    old_len
                })
                .collect::<Vec<usize>>();
            for (j, item) in self.data.iter().enumerate() {
                if j % sizes[1] == 0 {
                    the_str += "\n";
                    the_str += &util::Encodeable::encode(item);
                    if j != self.data.len() - 1 {
                        the_str += ",";
                    }
                } else {
                    the_str += &util::Encodeable::encode(item);
                    the_str += ",";
                }
            }
            write!(f, "{}", the_str)
        } else {
            let mut the_str = String::new();
            for (j, item) in self.data.iter().enumerate() {
                if j == self.data.len() - 1 {
                    the_str += &util::Encodeable::encode(item);
                } else {
                    the_str += &util::Encodeable::encode(item);
                    the_str += ",";
                }
            }
            write!(f, "{}", the_str)
        }
    }
}

impl<CellDataType: Clone + util::Encodeable> GridDataType<CellDataType> {
    /// Function `new` creates a blank `GridDataType`
    pub fn new() -> Self {
        Self {
            data: Vec::new(),
            dimensions: Vec::new(),
        }
    }
    /// Function `from_data` creates a blank `GridDataType` from a slice of data and a slice of usize's representing the dimensions
    pub fn from_data(data: &[util::NanoVec<CellDataType>], dims: &[usize]) -> Self {
        Self {
            data: data.to_vec(),
            dimensions: dims.to_vec(),
        }
    }
    /// Function `get_data_ref` returns a reference to the data inside the grid
    pub fn get_data_ref(&self) -> &Vec<util::NanoVec<CellDataType>> {
        &self.data
    }
    /// Function `get_data_mut_ref` returns a mutable reference to the data inside the grid
    pub fn get_data_mut_ref(&mut self) -> &mut Vec<util::NanoVec<CellDataType>> {
        &mut self.data
    }
    pub fn get_data_mut_slice(&mut self) -> &mut [util::NanoVec<CellDataType>] {
        self.data.as_mut_slice()
    }
    pub fn get_data_copy(&self) -> Vec<util::NanoVec<CellDataType>> {
        self.data.clone()
    }
    pub fn get_mut_references(
        &mut self,
        num_chunks: usize,
    ) -> Vec<Option<&mut [util::NanoVec<CellDataType>]>> {
        let mut to_return: Vec<Option<&mut [util::NanoVec<CellDataType>]>> = Vec::new();
        let data_length = self.get_data_ref().len();
        let chunk_size = data_length / num_chunks;
        let mut previous = self.get_data_mut_ref().as_mut_slice();
        for _ in 0..num_chunks - 1 {
            let cut = previous.split_at_mut(chunk_size);
            to_return.push(Some(cut.0));
            previous = cut.1;
        }
        to_return.push(Some(previous));
        to_return
    }
}

impl<'a, CellDataType: Clone + util::Encodeable> NeighborType<'a, CellDataType> {
    pub fn new(
        data: Vec<&'a util::NanoVec<CellDataType>>,
        dimensions: &'a [usize],
    ) -> NeighborType<'a, CellDataType> {
        NeighborType { data, dimensions }
    }
    pub fn get_data(&self) -> Vec<&'a util::NanoVec<CellDataType>> {
        self.data.clone()
    }
    pub fn get_data_ref(&self) -> &Vec<&'a util::NanoVec<CellDataType>> {
        &self.data
    }
}