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::traits::{Runnable, SimObject};
20use gwr_engine::types::{SimError, SimResult};
21use gwr_model_builder::EntityDisplay;
22use gwr_track::entity::Entity;
23use gwr_track::trace;
24
25use crate::types::Credit;
26use crate::{connect_tx, port_rx, take_option};
27
28#[derive(EntityDisplay)]
29pub struct CreditIssuer<T>
30where
31    T: SimObject,
32{
33    pub entity: Rc<Entity>,
34    tx: RefCell<Option<OutPort<T>>>,
35    credit_tx: RefCell<Option<OutPort<Credit>>>,
36    rx: RefCell<Option<InPort<T>>>,
37}
38
39impl<T> CreditIssuer<T>
40where
41    T: SimObject,
42{
43    pub fn new_and_register(engine: &Engine, parent: &Rc<Entity>) -> Result<Rc<Self>, SimError> {
44        let entity = Rc::new(Entity::new(parent, "credit_issue"));
45        let tx = OutPort::new(&entity, "tx");
46        let credit_tx = OutPort::new(&entity, "credit_tx");
47        let rx = InPort::new(&entity, "rx");
48        let rc_self = Rc::new(Self {
49            entity,
50            tx: RefCell::new(Some(tx)),
51            credit_tx: RefCell::new(Some(credit_tx)),
52            rx: RefCell::new(Some(rx)),
53        });
54        engine.register(rc_self.clone());
55        Ok(rc_self)
56    }
57
58    pub fn connect_port_tx(&self, port_state: PortStateResult<T>) -> SimResult {
59        connect_tx!(self.tx, connect ; port_state)
60    }
61
62    pub fn port_rx(&self) -> PortStateResult<T> {
63        port_rx!(self.rx, state)
64    }
65
66    pub fn connect_port_credit_tx(&self, port_state: PortStateResult<Credit>) -> SimResult {
67        connect_tx!(self.credit_tx, connect ; port_state)
68    }
69}
70
71#[async_trait(?Send)]
72impl<T> Runnable for CreditIssuer<T>
73where
74    T: SimObject,
75{
76    async fn run(&self) -> SimResult {
77        let rx = take_option!(self.rx);
78        let credit_tx = take_option!(self.credit_tx);
79        let tx = take_option!(self.tx);
80
81        loop {
82            let value = rx.get()?.await;
83            trace!(self.entity ; "issue credit");
84            credit_tx.put(Credit(1))?.await;
85            tx.put(value)?.await;
86        }
87    }
88}