dvcompute_gpss_dist/simulation/block/
basic.rs

1// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use dvcompute_dist::simulation::event::*;
8use dvcompute_dist::simulation::process::*;
9
10use dvcompute_utils::grc::Grc;
11
12use crate::simulation::block::*;
13use crate::simulation::queue::*;
14use crate::simulation::facility::*;
15use crate::simulation::transact::*;
16
17/// The Advance block to simulate some activity.
18#[inline]
19pub fn advance_block<M, T>(comp: M) -> impl Block<Input = T, Output = T> + Clone
20    where M: Process<Item = ()> + Clone + 'static,
21          T: Clone + 'static
22{
23    cons_block(move |x| {
24        comp.map(move |()| x)
25    })
26}
27
28/// The Queue block to enqueue.
29#[inline]
30pub fn queue_block<T>(queue: Grc<Queue>, increment: isize) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
31    where T: Clone + 'static
32{
33    cons_block(move |x: Transact<T>| {
34        Queue::enqueue(queue, x.transact_id.clone(), increment)
35            .map(move |()| x)
36            .into_process()
37    })
38}
39
40/// The Depart block to depart from the queue.
41#[inline]
42pub fn depart_block<T>(queue: Grc<Queue>, decrement: isize) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
43    where T: Clone + 'static
44{
45    cons_block(move |x: Transact<T>| {
46        Queue::dequeue(queue, x.transact_id.clone(), decrement)
47            .map(move |()| x)
48            .into_process()
49    })
50}
51
52/// The Seize block to seize the facility.
53#[inline]
54pub fn seize_block<T>(facility: Grc<Facility<T>>) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
55    where T: Clone + 'static
56{
57    cons_block(move |x: Transact<T>| {
58        seize_facility(facility, x.clone())
59            .map(move |()| x)
60            .into_process()
61    })
62}
63
64/// The Release block to release the facility.
65#[inline]
66pub fn release_block<T>(facility: Grc<Facility<T>>) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
67    where T: Clone + 'static
68{
69    cons_block(move |x: Transact<T>| {
70        release_facility(facility, x.transact_id.clone())
71            .map(move |()| x)
72            .into_process()
73    })
74}
75
76/// The Return block to release the facility.
77#[inline]
78pub fn return_block<T>(facility: Grc<Facility<T>>) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
79    where T: Clone + 'static
80{
81    cons_block(move |x: Transact<T>| {
82        return_facility(facility, x.transact_id.clone())
83            .map(move |()| x)
84            .into_process()
85    })
86}
87
88/// The Preempt block to preempt the facility.
89#[inline]
90pub fn preempt_block<T>(facility: Grc<Facility<T>>, mode: PreemptBlockMode<T>) -> impl Block<Input = Transact<T>, Output = Transact<T>> + Clone
91    where T: Clone + 'static
92{
93    cons_block(move |x: Transact<T>| {
94        preempt_facility(facility, x.clone(), mode.into())
95            .map(move |()| x)
96            .into_process()
97    })
98}
99
100/// The Preempt block mode.
101#[derive(Clone)]
102pub struct PreemptBlockMode<T> {
103
104    /// The Priority mode; otherwise, the Interrupt mode.
105    pub priority_mode: bool,
106
107    /// Where to transfer the preempted transact,
108    /// passing in the remaining time from the process holding
109    /// computation such as the Advance block.
110    pub transfer: Option<PreemptBlockTransfer<T>>,
111
112    /// The Remove mode.
113    pub remove_mode: bool
114}
115
116impl<T> From<FacilityPreemptMode<T>> for PreemptBlockMode<T>
117    where T: Clone + 'static
118{
119    fn from(mode: FacilityPreemptMode<T>) -> Self {
120        let FacilityPreemptMode { priority_mode, transfer, remove_mode } = mode;
121        let transfer = match transfer {
122            None => None,
123            Some(f) => Some({
124                PreemptBlockTransfer::new(move |dt| {
125                    cons_block(move |transact| {
126                        f.call_box((transact, dt))
127                    }).into_boxed()
128                })
129            })
130        };
131
132        PreemptBlockMode {
133            priority_mode: priority_mode,
134            transfer: transfer,
135            remove_mode: remove_mode
136        }
137    }
138}
139
140/// Proceed with the computation by the specified preempted transact
141/// and remaining time from the process holding computation such as the Advance block.
142pub struct PreemptBlockTransfer<T> {
143    f: Box<dyn PreemptBlockTransferFnBoxClone<T>>
144}
145
146impl<T> PreemptBlockTransfer<T> {
147
148    /// Create a new transfer.
149    #[inline]
150    pub fn new<F>(f: F) -> Self
151        where F: FnOnce(Option<f64>) -> BlockBox<Transact<T>, ()> + Clone + 'static,
152              T: 'static
153    {
154        PreemptBlockTransfer {
155            f: Box::new(f)
156        }
157    }
158
159    /// Call the boxed function.
160    #[inline]
161    pub fn call_box(self, arg: Option<f64>) -> BlockBox<Transact<T>, ()> {
162        let PreemptBlockTransfer { f } = self;
163        f.call_box(arg)
164    }
165}
166
167impl<T> Clone for PreemptBlockTransfer<T> {
168
169    #[inline]
170    fn clone(&self) -> Self {
171        PreemptBlockTransfer {
172            f: self.f.call_clone()
173        }
174    }
175}
176
177/// A trait to support the stable version of Rust, where there is no `FnBox`.
178trait PreemptBlockTransferFnBox<T> {
179
180    /// Call the corresponding function.
181    fn call_box(self: Box<Self>, args: Option<f64>) -> BlockBox<Transact<T>, ()>;
182}
183
184impl<T, F> PreemptBlockTransferFnBox<T> for F
185    where F: FnOnce(Option<f64>) -> BlockBox<Transact<T>, ()>,
186          T: 'static
187{
188    fn call_box(self: Box<Self>, args: Option<f64>) -> BlockBox<Transact<T>, ()> {
189        let this: Self = *self;
190        this(args)
191    }
192}
193
194/// A trait to implement a cloneable `FnBox`.
195trait PreemptBlockTransferFnBoxClone<T>: PreemptBlockTransferFnBox<T> {
196
197    /// Clone the function.
198    fn call_clone(&self) -> Box<dyn PreemptBlockTransferFnBoxClone<T>>;
199}
200
201impl<T, F> PreemptBlockTransferFnBoxClone<T> for F
202    where F: FnOnce(Option<f64>) -> BlockBox<Transact<T>, ()> + Clone + 'static,
203          T: 'static
204{
205    fn call_clone(&self) -> Box<dyn PreemptBlockTransferFnBoxClone<T>> {
206        Box::new(self.clone())
207    }
208}