gwr_components/flow_controls/
credit_issuer.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! Issue credit to a
4//! [credit limiter](crate::flow_controls::credit_limiter)
5//! for an output port.
6//!
7//! # Ports
8//!
9//! This component has the following ports:
10//!  - One [input port](gwr_engine::port::InPort): `rx`
11//!  - Two [output ports](gwr_engine::port::OutPort): `tx`, `credit_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::{InPort, OutPort, PortStateResult};
19use gwr_engine::time::clock::Clock;
20use gwr_engine::traits::{Runnable, SimObject};
21use gwr_engine::types::{SimError, SimResult};
22use gwr_model_builder::{EntityDisplay, EntityGet};
23use gwr_track::entity::Entity;
24use gwr_track::trace;
25use gwr_track::tracker::aka::Aka;
26
27use crate::types::Credit;
28use crate::{connect_tx, port_rx, take_option};
29
30#[derive(EntityGet, EntityDisplay)]
31pub struct CreditIssuer<T>
32where
33    T: SimObject,
34{
35    entity: Rc<Entity>,
36    tx: RefCell<Option<OutPort<T>>>,
37    credit_tx: RefCell<Option<OutPort<Credit>>>,
38    rx: RefCell<Option<InPort<T>>>,
39}
40
41impl<T> CreditIssuer<T>
42where
43    T: SimObject,
44{
45    pub fn new_and_register_with_renames(
46        engine: &Engine,
47        clock: &Clock,
48        parent: &Rc<Entity>,
49        name: &str,
50        aka: Option<&Aka>,
51    ) -> Result<Rc<Self>, SimError> {
52        let entity = Rc::new(Entity::new(parent, name));
53        let tx = OutPort::new_with_renames(&entity, "tx", aka);
54        let credit_tx = OutPort::new_with_renames(&entity, "credit_tx", aka);
55        let rx = InPort::new_with_renames(engine, clock, &entity, "rx", aka);
56        let rc_self = Rc::new(Self {
57            entity,
58            tx: RefCell::new(Some(tx)),
59            credit_tx: RefCell::new(Some(credit_tx)),
60            rx: RefCell::new(Some(rx)),
61        });
62        engine.register(rc_self.clone());
63        Ok(rc_self)
64    }
65
66    pub fn new_and_register(
67        engine: &Engine,
68        clock: &Clock,
69        parent: &Rc<Entity>,
70        name: &str,
71    ) -> Result<Rc<Self>, SimError> {
72        Self::new_and_register_with_renames(engine, clock, parent, name, None)
73    }
74
75    pub fn connect_port_tx(&self, port_state: PortStateResult<T>) -> SimResult {
76        connect_tx!(self.tx, connect ; port_state)
77    }
78
79    pub fn port_rx(&self) -> PortStateResult<T> {
80        port_rx!(self.rx, state)
81    }
82
83    pub fn connect_port_credit_tx(&self, port_state: PortStateResult<Credit>) -> SimResult {
84        connect_tx!(self.credit_tx, connect ; port_state)
85    }
86}
87
88#[async_trait(?Send)]
89impl<T> Runnable for CreditIssuer<T>
90where
91    T: SimObject,
92{
93    async fn run(&self) -> SimResult {
94        let rx = take_option!(self.rx);
95        let credit_tx = take_option!(self.credit_tx);
96        let tx = take_option!(self.tx);
97
98        loop {
99            let value = rx.get()?.await;
100            trace!(self.entity ; "issue credit");
101            credit_tx.put(Credit(1))?.await;
102            tx.put(value)?.await;
103        }
104    }
105}