osiris-data 0.2.1

A data management package.
Documentation
//! This module exposes data structures composed of [Word]s.
//!
//! The [ProduceConsume] trait helps create function which can accept any stack or queue-like structure.
//!
//! The [WordStack], [WordQueue] and [Array] structures help process operations with memory. 

use std::collections::VecDeque;
use std::ops::{Index, IndexMut};
use std::slice::Iter;
use std::vec::IntoIter;

use crate::data::atomic::Word;
use crate::data::identification::{Address, Area, Cursor, Identifier};


/// Common trait for data structure usable as a producer-consumer medium.
pub trait ProduceConsume<T> {
    /// Produce a value.
    ///
    /// This method adds a value into the object.
    fn produce(&mut self, data: T);

    /// Consume a value.
    ///
    /// This method moves out a value from the object.
    fn consume(&mut self) -> Option<T>;
    fn len(&self) -> usize;
    fn is_empty(&self) -> bool;
}


/// Describes a contiguous area in memory composed of [Word]s.
#[derive(Clone, Debug, Default)]
pub struct Array {
    data: Vec<Word>,
}

impl Array {
    /// Creates a new array composed of zeros.
    pub fn new(size: usize) -> Self {
        let mut array = Self { data: Vec::new() };
        array.data.resize(size, Word::default());
        array
    }

    /// Creates a new array from a slice of [Word]s.
    pub fn from(arr: &[Word]) -> Self {
        Self { data: arr.to_vec() }
    }

    /// Gets a subset of the current array.
    pub fn sub(&self, ignore_start: Address, ignore_end: Address) -> Self {
        Self::from(&self.as_slice()[ignore_start.to_usize()..(self.len() - ignore_end.to_usize())])
    }

    /// Gets a subset of the current array with its end trimmed.
    pub fn sub_from_start(&self, ignore_end: Address) -> Self { self.sub(Address::default(), ignore_end) }

    /// Gets a subset of the current array with its start trimmed.
    pub fn sub_from_end(&self, ignore_start: Address) -> Self { self.sub(ignore_start, Address::default()) }

    /// Returns `([..cesure], [cesure..])`.
    pub fn split(&self, cesure: Address) -> (Array, Array) {
        let mut first = Array::new(0);
        let mut second = Array::new(0);
        let mut index = Address::default();
        while let Some(word) = self.next(&mut index) {
            if index < cesure {
                first.push(word);
            } else {
                second.push(word);
            }
        }
        (first, second)
    }

    /// Returns a slice that shares the raw [Word]s data.
    pub fn as_slice(&self) -> &[Word] { &self.data }

    /// Returns a slice that shares the raw [Word]s data.
    pub fn as_mut_slice(&mut self) -> &mut [Word] { &mut self.data }

    /// Returns Some(Word) at the corresponding index.
    pub fn next(&self, index: &mut Address) -> Option<Word> {
        let output = self.data.get(index.to_usize()).cloned();
        index.increment();
        output
    }

    /// Returns an iterator that gives immutable references to the elements in the collection in sequence.
    pub fn iter(&self) -> Iter<Word> { self.data.iter() }

    /// Returns the number of words in the array.
    pub fn len(&self) -> usize { self.data.len() }

    /// Returns true if the array contains no elements.
    pub fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Appends an element to the end of the array.
    pub fn push(&mut self, value: Word) { self.data.push(value); }

    /// Inserts an element to the array at a specific position.
    ///
    /// Assumes that 'address' can be converted to a position in the array.
    pub fn insert(&mut self, address: Address, value: Word) { self.data.insert(address.to_usize(), value); }

    /// Removes and returns the element at position 'index' in the array.
    ///
    /// Assumes that 'index' can be converted to a valid position in the array.
    pub fn remove(&mut self, index: Address) -> Word { self.data.remove(index.to_usize()) }

    /// Merges the current array with a borrowed array.
    pub fn merge(&mut self, with: &Array) {
        self.data.extend_from_slice(with.as_slice());
    }

    /// Extract an array covering a whole area.
    pub fn extract(&self, area: Area) -> Array { self.sub(area.start(), area.end()) }

    /// Extract one word inside an area from the array.
    pub fn extract_word(&self, area: Area, cursor: Address) -> Word { self[area.constraint(cursor)] }

    /// Extract one word from a cursor reference and advances it.
    pub fn next_word(&self, mut cursor: Cursor) -> (Word, Cursor) {
        let data = self[cursor.area.constraint(cursor.current())];
        cursor.advance();
        (data, cursor)
    }
}

impl IntoIterator for Array {
    type Item = Word;
    type IntoIter = IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter { self.data.into_iter() }
}

impl Index<Address> for Array {
    type Output = Word;
    fn index(&self, index: Address) -> &Self::Output { &self.data[index.to_usize()] }
}

impl IndexMut<Address> for Array {
    fn index_mut(&mut self, index: Address) -> &mut Self::Output { &mut self.data[index.to_usize()] }
}

/// Describes a queue (First In-First Out) composed of [Word]s.
#[derive(Clone, Debug, Default)]
pub struct WordQueue {
    raw: VecDeque<Word>,
}

impl WordQueue {
    /// Creates an empty queue.
    pub fn new() -> Self { Self::default() }
}

impl ProduceConsume<Word> for WordQueue {
    /// Adds a word at the end of the queue.
    fn produce(&mut self, word: Word) { self.raw.push_back(word); }

    /// Removes and returns an item from the end of the queue.
    fn consume(&mut self) -> Option<Word> { self.raw.pop_front() }

    /// Returns the queue length.
    fn len(&self) -> usize { self.raw.len() }

    /// Returns true if the queue has a zero length.
    fn is_empty(&self) -> bool { self.len() == 0 }
}

/// Describes a stack (Last In-First Out) composed of [Word]s.
#[derive(Clone, Debug, Default)]
pub struct WordStack {
    raw: Vec<Word>,
}

impl WordStack {
    /// Creates an empty stack.
    pub fn new() -> Self { Self::default() }
}

impl ProduceConsume<Word> for WordStack {
    fn produce(&mut self, word: Word) { self.raw.push(word); }
    fn consume(&mut self) -> Option<Word> { self.raw.pop() }
    fn len(&self) -> usize { self.raw.len() }
    fn is_empty(&self) -> bool { self.len() == 0 }
}