1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
// Copyright (C) 2017 Jesse Jones // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. use std; use std::fmt; /// `Component`s are the building blocks of a `Simulation`. They are arranged into /// a tree and use a thread to respond to `Event`s which execute at some particular /// `Time`. Note that, in general, all state managed within components should be /// stored in the `Store`. This makes it possible to use GUI tools to see what is /// happening within components and even more importantly allows the Simulation to /// perform speculative execution of components. /// /// Typically type safe structs are defined for components with the aid of [`OutPort`], /// [`InPort`], [`IntValue`], etc. pub struct Component { /// The name of the component. Note that, in general, these are not unique. pub name: String, /// ID for the component's parent. The root component will return NO_COMPONENT. pub parent: ComponentID, pub children: Vec<ComponentID>, } /// To make lifetime management easier components are referenced using a small /// integer instead of a rust reference. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct ComponentID(pub usize); /// The id of the root component. pub const NO_COMPONENT: ComponentID = ComponentID(std::usize::MAX); impl fmt::Display for ComponentID { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{}", self.0) } } /// Typically `Component` threads will use this to cut down on the boiler plate involved in /// processing dispatched `Event`s. Note that this will panic if it tries to process an /// event that doesn't have an associated code block. /// /// # Examples /// /// ``` /// use score::*; /// use std::thread; /// /// fn my_thread(data: ThreadData) /// { /// thread::spawn(move || { /// process_events!(data, event, state, effector, /// "init 0" => { /// // Use the effector to change the simulation state. /// let event = Event::new("timer"); /// effector.schedule_after_secs(event, data.id, 1.0); /// }, /// "timer" => { /// // Typically you'd re-schedule the timer here, /// log_info!(effector, "timer fired!"); /// } /// ); /// }); /// } /// ``` #[macro_export] macro_rules! process_events { ($data:expr, $event:ident, $state:ident, $effector:ident, $($name:pat => $code:expr),+) => ({ for ($event, $state) in $data.rx.iter() { let mut $effector = Effector::new(); { let ename = &$event.name; match ename.as_ref() { $($name => $code)+ _ => { let cname = &(*$state.components).get($data.id).name; panic!("component {} can't handle event {}", cname, ename); } } } drop($state); // we need to do this before the send to ensure that our references are dropped before the Simulator processes the send let _ = $data.tx.send($effector); } }); }