gwr_components/store/
mod.rs1use std::cell::RefCell;
17use std::collections::VecDeque;
18use std::rc::Rc;
19
20use async_trait::async_trait;
21use gwr_engine::engine::Engine;
22use gwr_engine::events::repeated::Repeated;
23use gwr_engine::executor::Spawner;
24use gwr_engine::port::{InPort, OutPort, PortStateResult};
25use gwr_engine::sim_error;
26use gwr_engine::time::clock::Clock;
27use gwr_engine::traits::{Event, Runnable, SimObject};
28use gwr_engine::types::{SimError, SimResult};
29use gwr_model_builder::{EntityDisplay, EntityGet};
30use gwr_track::entity::Entity;
31use gwr_track::tracker::aka::Aka;
32
33use crate::{connect_tx, port_rx, take_option};
34
35mod byte_store;
36mod object_store;
37
38pub use byte_store::ByteStore;
39pub use object_store::ObjectStore;
40
41type ObjectToCapacity<T> = fn(&T) -> usize;
42
43struct State<T>
44where
45 T: SimObject,
46{
47 entity: Rc<Entity>,
48 capacity: usize,
49 capacity_unit: RefCell<String>,
50 used: RefCell<usize>,
51 data: RefCell<VecDeque<T>>,
52 error_on_overflow: RefCell<bool>,
53 level_change: Repeated<usize>,
54 object_to_capacity: ObjectToCapacity<T>,
55}
56
57impl<T> State<T>
58where
59 T: SimObject,
60{
61 fn new(entity: &Rc<Entity>, capacity: usize, object_to_capacity: ObjectToCapacity<T>) -> Self {
62 Self {
63 entity: entity.clone(),
64 capacity,
65 capacity_unit: RefCell::new("objects".to_string()),
66 used: RefCell::new(0),
67 data: RefCell::new(VecDeque::new()),
68 error_on_overflow: RefCell::new(false),
69 level_change: Repeated::new(usize::default()),
70 object_to_capacity,
71 }
72 }
73
74 fn has_capacity_for(&self, units: usize) -> bool {
75 units <= self.capacity - *self.used.borrow()
76 }
77
78 fn check_units_can_fit(&self, units: usize) -> SimResult {
79 if units > self.capacity {
80 let capacity_unit = self.capacity_unit.borrow();
81 return sim_error!(
82 "Cannot store {units} {capacity_unit} in {:?} with capacity {}",
83 self.entity.full_name(),
84 self.capacity
85 );
86 }
87 Ok(())
88 }
89
90 fn push_value(&self, value: T) -> SimResult {
91 let units = (self.object_to_capacity)(&value);
92 self.entity.track_enter(value.id());
93 if *self.error_on_overflow.borrow() {
94 if !self.has_capacity_for(units) {
95 return sim_error!("Overflow in {:?}", self.entity.full_name());
96 }
97 } else {
98 assert!(self.has_capacity_for(units));
99 }
100
101 self.data.borrow_mut().push_back(value);
102 *self.used.borrow_mut() += units;
103 self.level_change.notify_result(*self.used.borrow());
104 Ok(())
105 }
106
107 fn pop_value(&self) -> Result<T, SimError> {
108 let value = self.data.borrow_mut().pop_front().unwrap();
109 *self.used.borrow_mut() -= (self.object_to_capacity)(&value);
110 self.level_change.notify_result(*self.used.borrow());
111 self.entity.track_exit(value.id());
112 Ok(value)
113 }
114}
115
116#[derive(EntityGet, EntityDisplay)]
121pub struct Store<T>
122where
123 T: SimObject,
124{
125 entity: Rc<Entity>,
126 spawner: Spawner,
127 state: Rc<State<T>>,
128 tx: RefCell<Option<OutPort<T>>>,
129 rx: RefCell<Option<InPort<T>>>,
130}
131
132impl<T> Store<T>
133where
134 T: SimObject,
135{
136 fn new(
137 engine: &Engine,
138 clock: &Clock,
139 entity: &Rc<Entity>,
140 aka: Option<&Aka>,
141 capacity: usize,
142 object_to_capacity: ObjectToCapacity<T>,
143 ) -> Result<Self, SimError> {
144 if capacity == 0 {
145 return sim_error!("Unsupported Store with capacity of 0");
146 }
147 Ok(Self {
148 entity: entity.clone(),
149 spawner: engine.spawner(),
150 state: Rc::new(State::new(entity, capacity, object_to_capacity)),
151 tx: RefCell::new(Some(OutPort::new_with_renames(entity, "tx", aka))),
152 rx: RefCell::new(Some(InPort::new_with_renames(
153 engine, clock, entity, "rx", aka,
154 ))),
155 })
156 }
157
158 pub fn connect_port_tx(&self, port_state: PortStateResult<T>) -> SimResult {
159 connect_tx!(self.tx, connect ; port_state)
160 }
161
162 pub fn port_rx(&self) -> PortStateResult<T> {
163 port_rx!(self.rx, state)
164 }
165
166 #[must_use]
167 pub fn capacity_used(&self) -> usize {
168 *self.state.used.borrow()
169 }
170
171 pub fn set_error_on_overflow(&self) {
172 *self.state.error_on_overflow.borrow_mut() = true;
173 }
174
175 pub fn set_capacity_unit(&self, capacity_unit: impl Into<String>) {
176 *self.state.capacity_unit.borrow_mut() = capacity_unit.into();
177 }
178
179 #[must_use]
180 pub fn get_level_change_event(&self) -> Repeated<usize> {
181 self.state.level_change.clone()
182 }
183}
184
185#[async_trait(?Send)]
186impl<T> Runnable for Store<T>
187where
188 T: SimObject,
189{
190 async fn run(&self) -> SimResult {
191 let rx = take_option!(self.rx);
192 let state = self.state.clone();
193 self.spawner.spawn(async move { run_rx(rx, state).await });
194
195 let tx = take_option!(self.tx);
196 let state = self.state.clone();
197 self.spawner.spawn(async move { run_tx(tx, state).await });
198 Ok(())
199 }
200}
201
202async fn run_rx<T>(mut rx: InPort<T>, state: Rc<State<T>>) -> SimResult
203where
204 T: SimObject,
205{
206 let level_change = state.level_change.clone();
207 loop {
208 let value = rx.start_get()?.await;
209 let units = (state.object_to_capacity)(&value);
210 state.check_units_can_fit(units)?;
211 while !state.has_capacity_for(units) && !*state.error_on_overflow.borrow() {
212 level_change.listen().await;
213 }
214 state.push_value(value)?;
215 rx.finish_get();
216 }
217}
218
219async fn run_tx<T>(mut tx: OutPort<T>, state: Rc<State<T>>) -> SimResult
220where
221 T: SimObject,
222{
223 let level_change = state.level_change.clone();
224 loop {
225 let level = state.data.borrow().len();
226 if level > 0 {
227 tx.try_put()?.await;
228 let value = state.pop_value()?;
229 tx.put(value)?.await;
230 } else {
231 level_change.listen().await;
232 }
233 }
234}