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::convert::*;
use std::mem;

use libc::*;

use dvcompute_network::network::*;

use crate::simulation::comm::pid::LogicalProcessId;
use crate::simulation::comm::context::*;

/// Associates with the logical process inbox.
pub struct LogicalProcess {}

impl LogicalProcess {

    /// Run the simulation.
    pub fn run<F>(network: NetworkSupport, pids: &[LogicalProcessId], ps: LogicalProcessParameters, f: F)
        where F: FnOnce(&LogicalProcessContext) + Send + 'static
    {
        unsafe {
            let ps = LogicalProcessParametersRepr::new(ps);
            let ps = Box::new(ps);
            let ps = Box::into_raw(ps);
            let f = LogicalProcessBox::new(f);
            let f = LogicalProcessRepr::into_repr(f);

            let pids: Vec<c_int> = pids.iter().map(|x| x.rank()).collect();
            let pid_ptr = pids.as_ptr();
            let pid_count = pids.len().try_into().unwrap();

            run_extern_logical_process(network, pid_ptr, pid_count, ps, f)
        }
    }
}

/// It represents the boxed logical process computation.
#[must_use = "computations are lazy and do nothing unless to be run"]
pub struct LogicalProcessBox {
    f: Box<dyn LogicalProcessFnBox>
}

impl LogicalProcessBox {

    /// Create a new boxed computation.
    #[doc(hidden)]
    #[inline]
    pub fn new<F>(f: F) -> Self
        where F: FnOnce(&LogicalProcessContext) + Send + 'static
    {
        LogicalProcessBox {
            f: Box::new(f)
        }
    }

    /// Call the boxed function.
    #[doc(hidden)]
    #[inline]
    pub fn call_box(self, arg: (&LogicalProcessContext,)) {
        let LogicalProcessBox { f } = self;
        f.call_box(arg)
    }
}

/// A trait to support.
trait LogicalProcessFnBox {

    /// Call the corresponding function.
    fn call_box(self: Box<Self>, args: (&LogicalProcessContext,));
}

impl<F> LogicalProcessFnBox for F
    where F: for<'a> FnOnce(&'a LogicalProcessContext)
{
    fn call_box(self: Box<Self>, args: (&LogicalProcessContext,)) {
        let this: Self = *self;
        this(args.0)
    }
}

/// It represents a raw trait object.
#[repr(C)]
#[derive(Copy, Clone)]
struct LogicalProcessTraitObject {

    field1: *mut c_void,
    field2: *mut c_void
}

/// A C-friendly representaton of the `LogicaProcessBox` computation.
#[repr(C)]
pub struct LogicalProcessRepr {

    /// Delete the object.
    delete: unsafe extern "C" fn(obj: *mut LogicalProcessTraitObject),

    /// The callback.
    callback: unsafe extern "C" fn(obj: *mut LogicalProcessTraitObject, p: *const LogicalProcessContext),

    /// The trait object.
    trait_object: LogicalProcessTraitObject
}

impl Drop for LogicalProcessRepr {

    fn drop(&mut self) {
        unsafe {
            (self.delete)(&mut self.trait_object);
        }
    }
}

impl LogicalProcessRepr {

    /// Convert to a C-friendly representation.
    #[inline]
    pub fn into_repr(comp: LogicalProcessBox) -> LogicalProcessRepr {
        unsafe {
            LogicalProcessRepr {
                delete: delete_lp_repr,
                callback: call_lp_repr,
                trait_object: mem::transmute(comp)
            }
        }
    }

    /// Call the representation.
    #[inline]
    fn _call_repr(mut self, ctx: &LogicalProcessContext) {
        unsafe {
            (self.callback)(&mut self.trait_object, ctx);
            mem::forget(self);
        }
    }
}

/// Call the `LogicalProcessBox` representation.
unsafe extern "C" fn call_lp_repr(comp: *mut LogicalProcessTraitObject, ctx: *const LogicalProcessContext) {
    let comp: LogicalProcessBox = mem::transmute(*comp);
    comp.call_box((&*ctx,))
}

/// Delete the `LogicalProcessBox` representation.
unsafe extern "C" fn delete_lp_repr(comp: *mut LogicalProcessTraitObject) {
    let _: LogicalProcessBox = mem::transmute(*comp);
}

unsafe impl Send for LogicalProcessBox {}
unsafe impl Send for LogicalProcessRepr {}

#[cfg(all(feature="cons_mode", not(feature="cons_core_mode")))]
#[cfg_attr(windows, link(name = "dvcompute_core_cons.dll"))]
#[cfg_attr(not(windows), link(name = "dvcompute_core_cons"))]
extern {

    /// Run the logical process.
    #[doc(hidden)]
    pub fn run_extern_logical_process(network: NetworkSupport, ranks: *const c_int, rank_count: c_int,
        ps: *mut LogicalProcessParametersRepr, f: LogicalProcessRepr);
}

#[cfg(all(feature="cons_mode", feature="cons_core_mode"))]
extern {

    /// Run the logical process.
    #[doc(hidden)]
    pub fn run_extern_logical_process(network: NetworkSupport, ranks: *const c_int, rank_count: c_int,
        ps: *mut LogicalProcessParametersRepr, f: LogicalProcessRepr);
}