dvcompute 2.0.0

Discrete event simulation library (sequential simulation)
Documentation
// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::cell::UnsafeCell;
use std::ptr;

use crate::simulation;
use crate::simulation::point::Point;
use crate::simulation::event::Event;

use dvcompute_utils::grc::Grc;

/// A mutable cell computation synchronized with the event queue.
pub struct RefComp<T> {

    /// The underlying cell.
    cell: UnsafeCell<T>
}

impl<T> RefComp<T> {

    /// Create a new mutable cell by the initial value.
    #[inline]
    pub fn new(val: T) -> RefComp<T> {
        RefComp { cell: UnsafeCell::new(val) }
    }

    /// Read the contents of the mutable cell at the specified time point.
    #[inline]
    pub fn read_at(&self, _p: &Point) -> T
        where T: Clone
    {
        let p = self.cell.get();
        unsafe {
            (*p).clone()
        }
    }

    /// Read the contents of the mutable cell within the `Event` computation.
    #[inline]
    pub fn read(comp: Grc<Self>) -> Read<T>
        where T: Clone
    {
        Read { comp: comp }
    }

    /// Swap the contents of the mutable cell at the specified time point.
    #[inline]
    pub fn swap_at(&self, val: T, _p: &Point) -> T {
        let mut t = val;
        unsafe {
            ptr::swap(&mut t, self.cell.get());
        }
        t
    }

    /// Swap the contents of the mutable cell within the `Event` computation.
    #[inline]
    pub fn swap(comp: Grc<Self>, val: T) -> Swap<T> {
        Swap { comp: comp, val: val }
    }

    /// Write into the contents of the mutable cell at the specified time point.
    #[inline]
    pub fn write_at(&self, val: T, _p: &Point) {
        let p = self.cell.get();
        unsafe {
            *p = val;
        }
    }

    /// Write into the contents of the mutable cell within the `Event` computation.
    #[inline]
    pub fn write(comp: Grc<Self>, val: T) -> Write<T> {
        Write { comp: comp, val: val }
    }

    /// Mutate the contents of the mutable cell at the specified time point.
    #[inline]
    pub fn modify_at<F>(&self, f: F, _p: &Point)
        where F: FnOnce(&T) -> T,
              T: Clone
    {
        let p = self.cell.get();
        unsafe {
            let t = (*p).clone();
            *p = f(&t);
        }
    }

    /// Mutate the contents of the mutable cell within the `Event` computation.
    #[inline]
    pub fn modify<F>(comp: Grc<Self>, f: F) -> Modify<T, F>
        where F: FnOnce(&T) -> T,
              T: Clone
    {
        Modify { comp: comp, f: f }
    }
}

impl<T> PartialEq for RefComp<T> {

    fn eq(&self, other: &Self) -> bool {
        self.cell.get() == other.cell.get()
    }
}

impl<T> Eq for RefComp<T> {}

impl<T: Clone> Clone for RefComp<T> {

    fn clone(&self) -> Self {
        let p = self.cell.get();
        unsafe {
            let val = (*p).clone();
            RefComp { cell: UnsafeCell::new(val) }
        }
    }
}

/// It reads the contents of the mutable cell within the `Event` computation.
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Read<T> where T: 'static {

    /// The corresponding reference.
    comp: Grc<RefComp<T>>
}

impl<T: Clone> Event for Read<T> {

    type Item = T;

    #[inline]
    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
        let Read { comp } = self;
        Result::Ok(comp.read_at(p))
    }
}

/// It swaps the contents of the mutable cell within the `Event` computation.
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Swap<T> where T: 'static {

    /// The corresponding reference.
    comp: Grc<RefComp<T>>,

    /// A new value.
    val: T
}

impl<T> Event for Swap<T> {

    type Item = T;

    #[inline]
    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
        let Swap { comp, val } = self;
        Result::Ok(comp.swap_at(val, p))
    }
}

/// It writes into the contents of the mutable cell within the `Event` computation.
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Write<T> where T: 'static {

    /// The corresponding reference.
    comp: Grc<RefComp<T>>,

    /// A new value.
    val: T
}

impl<T> Event for Write<T> {

    type Item = ();

    #[inline]
    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
        let Write { comp, val } = self;
        Result::Ok(comp.write_at(val, p))
    }
}

/// It mutates the contents of the mutable cell within the `Event` computation.
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Modify<T, F> where T: 'static {

    /// The corresponding reference.
    comp: Grc<RefComp<T>>,

    /// A mutator.
    f: F
}

impl<T, F> Event for Modify<T, F>
    where F: FnOnce(&T) -> T,
          T: Clone
{
    type Item = ();

    #[inline]
    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
        let Modify { comp, f } = self;
        Result::Ok(comp.modify_at(f, p))
    }
}