gwr_components/
source.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! A data source.
4//!
5//! The data source produces data as defined by the [DataGenerator] that is
6//! provided.
7//!
8//! # Ports
9//!
10//! This component has:
11//!  - One [output port](gwr_engine::port::OutPort): `tx`
12
13use std::cell::RefCell;
14use std::rc::Rc;
15
16use async_trait::async_trait;
17use gwr_engine::engine::Engine;
18use gwr_engine::port::{OutPort, PortStateResult};
19use gwr_engine::traits::{Runnable, SimObject};
20use gwr_engine::types::{SimError, SimResult};
21use gwr_model_builder::EntityDisplay;
22use gwr_track::entity::Entity;
23use gwr_track::exit;
24
25#[macro_export]
26macro_rules! option_box_repeat {
27    ($value:expr ; $repeat:expr) => {
28        Some(Box::new(std::iter::repeat($value).take($repeat)))
29    };
30}
31use crate::types::DataGenerator;
32use crate::{connect_tx, take_option};
33
34#[macro_export]
35macro_rules! option_box_chain {
36    ($value1:expr , $value2:expr) => {
37        Some(Box::new((*($value1.unwrap())).chain(*($value2.unwrap()))))
38    };
39}
40
41#[derive(EntityDisplay)]
42pub struct Source<T>
43where
44    T: SimObject,
45{
46    pub entity: Rc<Entity>,
47    data_generator: RefCell<Option<DataGenerator<T>>>,
48    tx: RefCell<Option<OutPort<T>>>,
49}
50
51impl<T> Source<T>
52where
53    T: SimObject,
54{
55    pub fn new_and_register(
56        engine: &Engine,
57        parent: &Rc<Entity>,
58        name: &str,
59        data_generator: Option<DataGenerator<T>>,
60    ) -> Result<Rc<Self>, SimError> {
61        let entity = Rc::new(Entity::new(parent, name));
62        let tx = OutPort::new(&entity, "tx");
63        let rc_self = Rc::new(Self {
64            entity,
65            data_generator: RefCell::new(data_generator),
66            tx: RefCell::new(Some(tx)),
67        });
68        engine.register(rc_self.clone());
69        Ok(rc_self)
70    }
71
72    #[must_use]
73    pub fn entity(&self) -> &Rc<Entity> {
74        &self.entity
75    }
76
77    pub fn set_generator(&self, data_generator: Option<DataGenerator<T>>) {
78        *self.data_generator.borrow_mut() = data_generator;
79    }
80
81    pub fn connect_port_tx(&self, port_state: PortStateResult<T>) -> SimResult {
82        connect_tx!(self.tx, connect ; port_state)
83    }
84}
85
86#[async_trait(?Send)]
87impl<T> Runnable for Source<T>
88where
89    T: SimObject,
90{
91    async fn run(&self) -> SimResult {
92        let mut data_generator = match self.data_generator.borrow_mut().take() {
93            Some(data_generator) => data_generator,
94            None => return Ok(()),
95        };
96
97        let tx = take_option!(self.tx);
98        loop {
99            let value = data_generator.next();
100            if let Some(value) = value {
101                exit!(self.entity ; value.id());
102                tx.put(value)?.await;
103            } else {
104                break;
105            }
106        }
107        Ok(())
108    }
109}