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/.

//! This crate is a part of discrete event simulation framework DVCompute Simulator (registration
//! number 2021660590 of Rospatent). The `dvcompute` crate is destined for sequential simulation,
//! but the same code base is shared by the `dvcompute_cons` crate destined for conservative
//! distributed simulation.
//!
//! There are the following main crates: `dvcompute` (sequential simulation),
//! `dvcompute_dist` (optimistic distributed simulation),
//! `dvcompute_cons` (conservative distributed simulation) and
//! `dvcompute_branch` (nested simulation). All four crates are
//! very close. They are based on the same method.
//!
//! In case of conservative distributed simulation, it is expected that the `dvcompute_mpi`
//! and `dvcompute_core_cons` dynamic (shared) libraries can be found by the operating system, when
//! launching the executable file of the simulation model. 
//!
//! You can build the `dvcompute_mpi` library yourself from the
//! <https://gitflic.ru/project/dsorokin/dvcompute/file?file=src%2Fdvcompute_mpi_cdylib> sources
//! that require CMake, C++ compiler and some MPI implementation that you are going to use.
//!
//! But the `dvcompute_core_cons` dynamic library must satisfy the predefined binary interface as 
//! specified in the `dvcompute_cons` crate (the dynamic library must implement the event queue). 
//! You can request the author for the prebuilt version that implements this interface. 
//! This prebuilt version is a part of "Redistributable Code" portions of DVCompute Simulator.
//!
//! The simulation method is described in the author's article:
//! Sorokin David. DVCompute Simulator for discrete event simulation.
//! Prikladnaya informatika=Journal of Applied Informatics, 2021, vol.16, no.3, pp.93-108 (in Russian).
//! DOI: 10.37791/2687-0649-2021-16-3-93-108
//!
//! The main idea is to use continuations for modeling discontinuous processes. Such continuations are
//! themselves wrapped in the monad, for which there are easy-to-use combinators. This idea is inspired
//! by two sources: (1) combinators for futures that were in Rust before introducing the async/await 
//! syntax and (2) the Aivika simulation library that I developed in Haskell before.
//! 
//! Here is an example that defines a model of the machine that breaks down and then it is repaired:
//!
//! ```rust,no_run
//! # use dvcompute_utils::grc::Grc; 
//! # #[cfg(feature="cons_mode")]
//! # use dvcompute_cons::prelude::*;
//! # #[cfg(any(feature="seq_mode", feature="wasm_mode"))]
//! # use dvcompute::prelude::*;
//! const UP_TIME_MEAN: f64 = 1.0;
//! const REPAIR_TIME_MEAN: f64 = 0.5;
//!
//! fn machine_process(total_up_time: Grc<RefComp<f64>>) -> ProcessBox<()> {
//!    let total_up_time2 = total_up_time.clone();
//!    random_exponential_process(UP_TIME_MEAN)
//!        .and_then(move |up_time| {
//!            RefComp::modify(total_up_time, move |total_up_time| {
//!                total_up_time + up_time
//!            })
//!            .into_process()
//!            .and_then(move |()| {
//!                random_exponential_process_(REPAIR_TIME_MEAN)
//!            })
//!            .and_then(move |()| {
//!                machine_process(total_up_time2)
//!            })
//!        })
//!        .into_boxed()
//! }
//! ```
//! 
//! These computations are combined with help of the monadic bind. Such computations should be run later 
//! to take effect.
//!
//! You can find more examples in the author's repository: <https://gitflic.ru/project/dsorokin/dvcompute>.

#[cfg(feature="cons_mode")]
#[macro_use]
extern crate serde_derive;

#[cfg(feature="cons_mode")]
extern crate serde;

#[cfg(feature="cons_mode")]
extern crate bincode;

#[cfg(feature="cons_mode")]
extern crate log;

extern crate dvcompute_rand;
extern crate dvcompute_utils;

#[cfg(feature="cons_mode")]
extern crate dvcompute_network;

#[cfg(feature="cons_mode")]
use std::ffi::CString;

#[cfg(feature="cons_mode")]
use std::ptr;

#[cfg(feature="cons_mode")]
use libc::*;

/// The main simulation module.
pub mod simulation;

/// The prelude module.
pub mod prelude;

#[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 {

    /// Setup the simulator logger.
    #[doc(hidden)]
    fn extern_setup_simulator_logger(filter: log::LevelFilter,
        track_id: c_int,
        log_to_console: c_int,
        log_filename: *const c_char);
}

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

    /// Setup the simulator logger.
    #[doc(hidden)]
    fn extern_setup_simulator_logger(filter: log::LevelFilter,
        track_id: c_int,
        log_to_console: c_int,
        log_filename: *const c_char);
}

/// Setup the simulator logger.
#[cfg(feature="cons_mode")]
pub fn setup_simulator_logger(filter: log::LevelFilter,
    track_id: c_int,
    log_to_console: bool,
    log_filename: Option<String>)
{
    unsafe {
        let log_to_console = if log_to_console { 1 } else { 0 };
        match log_filename {
            None => {
                extern_setup_simulator_logger(filter, track_id, log_to_console, ptr::null_mut())
            },
            Some(log_filename) => {
                let log_filename = CString::new(log_filename).expect("NulError");
                let log_filename = CString::into_raw(log_filename);

                extern_setup_simulator_logger(filter, track_id, log_to_console, log_filename)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}