1use std::borrow::Borrow;
26#[cfg(not(feature = "no-unsafe"))]
27use std::cell::UnsafeCell;
28use std::collections::HashMap;
29use std::fmt::Debug;
30#[cfg(feature = "no-unsafe")]
31use std::ops::Deref;
32use std::ops::{DerefMut, Index, IndexMut};
33use std::rc::Rc;
34use std::time::Instant;
35
36use atomic_refcell::AtomicRefCell;
37use AssemblyErrorImpl::{CannotBind, CyclicDependency};
38
39use crate::assembly::{AssemblyError, AssemblyErrorImpl, PortId, PortKind, TriggerId, TriggerLike};
40use crate::{EventTag, ReactionTrigger};
41
42pub struct Port<T: Sync> {
60 id: TriggerId,
61 kind: PortKind,
62 bind_status: BindStatus,
63 upstream_binding: Rc<UncheckedCell<Rc<PortCell<T>>>>,
64 }
82
83impl<T: Sync> Port<T> {
84 pub(crate) fn new(id: TriggerId, kind: PortKind) -> Self {
86 Self {
87 id,
88 kind,
89 bind_status: BindStatus::Free,
90 #[cfg(feature = "no-unsafe")]
91 upstream_binding: Rc::new(AtomicRefCell::new(Default::default())),
92 #[cfg(not(feature = "no-unsafe"))]
93 upstream_binding: Rc::new(UnsafeCell::new(Default::default())),
94 }
95 }
96
97 pub(crate) fn is_present_now(&self) -> bool {
98 self.use_ref(|opt| opt.is_some())
99 }
100
101 pub(crate) fn get_kind(&self) -> PortKind {
102 self.kind
103 }
104 #[inline]
105 pub(crate) fn get(&self) -> Option<T>
106 where
107 T: Copy,
108 {
109 self.use_ref(Option::<T>::clone)
110 }
111
112 cfg_if! {
113 if #[cfg(feature = "no-unsafe")] {
114 pub(crate) fn use_ref<R>(&self, f: impl FnOnce(&Option<T>) -> R) -> R {
115 use atomic_refcell::AtomicRef;
116 let cell_ref: AtomicRef<Rc<PortCell<T>>> = AtomicRefCell::borrow(&self.upstream_binding);
117 let binding: &Rc<PortCell<T>> = cell_ref.deref();
118 let class_cell: &PortCell<T> = Rc::borrow(binding);
119 let cell_borrow: &AtomicRef<Option<T>> = &class_cell.value.borrow();
120
121 f(cell_borrow.deref())
122 }
123
124 pub(crate) fn set_impl(&mut self, new_value: Option<T>) {
128 use atomic_refcell::AtomicRef;
129
130 debug_assert_ne!(self.bind_status, BindStatus::Bound, "Cannot set a bound port ({:?})", self.id);
131
132 let cell_ref: AtomicRef<Rc<PortCell<T>>> = AtomicRefCell::borrow(&self.upstream_binding);
133 let class_cell: &PortCell<T> = Rc::borrow(cell_ref.deref());
134
135 *class_cell.value.borrow_mut() = new_value;
136 }
137
138 } else {
139
140 pub(crate) fn get_ref(&self) -> Option<&T> {
145 let binding: &UnsafeCell<Rc<PortCell<T>>> = Rc::borrow(&self.upstream_binding);
146 unsafe {
147 let cell = &*binding.get();
148 let opt = &*cell.value.get();
149 opt.as_ref()
150 }
151 }
152
153 #[inline]
154 pub(crate) fn use_ref<R>(&self, f: impl FnOnce(&Option<T>) -> R) -> R {
155 let binding: &UnsafeCell<Rc<PortCell<T>>> = Rc::borrow(&self.upstream_binding);
156 let opt: &Option<T> = unsafe {
157 let cell = &*binding.get();
158 &*cell.value.get()
159 };
160 f(opt)
161 }
162
163 #[inline]
164 pub(crate) fn set_impl(&mut self, new_value: Option<T>) {
165 debug_assert_ne!(self.bind_status, BindStatus::Bound, "Cannot set a bound port");
166
167 let binding: &UnsafeCell<Rc<PortCell<T>>> = Rc::borrow(&self.upstream_binding);
168
169 unsafe {
170 let cell: &Rc<PortCell<T>> = &*binding.get();
171 cell.value.get().replace(new_value);
173 }
174 }
175 }
176 }
177
178 #[inline]
180 pub(crate) fn clear_value(&mut self) {
181 if self.bind_status != BindStatus::Bound {
184 self.set_impl(None)
185 }
186 }
187
188 pub(crate) fn forward_to(&mut self, downstream: &mut Port<T>) -> Result<(), AssemblyError> {
189 let mut mut_downstream_cell = {
190 cfg_if! {
191 if #[cfg(feature = "no-unsafe")] {
192 (downstream.upstream_binding).borrow_mut()
193 } else {
194 unsafe { downstream.upstream_binding.get().as_mut().unwrap() }
195 }
196 }
197 };
198
199 if downstream.bind_status == BindStatus::Bound {
200 return Err(AssemblyError(CannotBind(self.id, downstream.id)));
201 }
202
203 downstream.bind_status = BindStatus::Bound;
204
205 let my_class = {
206 cfg_if! {
207 if #[cfg(feature = "no-unsafe")] {
208 self.upstream_binding.borrow_mut()
209 } else {
210 unsafe { self.upstream_binding.get().as_mut().unwrap() }
211 }
212 }
213 };
214
215 my_class
216 .downstreams
217 .borrow_mut()
218 .insert(downstream.id, Rc::clone(&downstream.upstream_binding));
219
220 let new_binding = Rc::clone(&my_class);
221
222 mut_downstream_cell.check_cycle(&self.id, &downstream.id)?;
223
224 mut_downstream_cell.set_upstream(&my_class);
225 *mut_downstream_cell.deref_mut() = new_binding;
226 Ok(())
227 }
228}
229
230impl<T: Sync> ReactionTrigger<T> for Port<T> {
231 #[inline]
232 fn is_present(&self, _now: &EventTag, _start: &Instant) -> bool {
233 self.is_present_now()
234 }
235
236 #[inline]
237 fn get_value(&self, _now: &EventTag, _start: &Instant) -> Option<T>
238 where
239 T: Copy,
240 {
241 self.get()
242 }
243
244 #[inline]
245 fn use_value_ref<O>(&self, _now: &EventTag, _start: &Instant, action: impl FnOnce(Option<&T>) -> O) -> O {
246 self.use_ref(|opt| action(opt.as_ref()))
247 }
248}
249
250#[cfg(not(feature = "no-unsafe"))]
251impl<T: Sync> crate::triggers::ReactionTriggerWithRefAccess<T> for Port<T> {
252 fn get_value_ref(&self, _now: &EventTag, _start: &Instant) -> Option<&T> {
253 self.get_ref()
254 }
255}
256
257impl<T: Sync> TriggerLike for Port<T> {
258 fn get_id(&self) -> TriggerId {
259 self.id
260 }
261}
262
263#[derive(Copy, Clone, Eq, PartialEq, Debug)]
264enum BindStatus {
265 Free,
267
268 Bound,
275}
276
277cfg_if! {
278 if #[cfg(feature = "no-unsafe")] {
279 type Downstreams<T> = AtomicRefCell<HashMap<PortId, Rc<AtomicRefCell<Rc<PortCell<T>>>>>>;
280 type UncheckedCell<T> = AtomicRefCell<T>;
281 } else {
282 type Downstreams<T> = AtomicRefCell<HashMap<PortId, Rc<UnsafeCell<Rc<PortCell<T>>>>>>;
283 type UncheckedCell<T> = UnsafeCell<T>;
284 }
285}
286
287struct PortCell<T: Sync> {
289 value: UncheckedCell<Option<T>>,
291
292 downstreams: Downstreams<T>,
309}
310
311impl<T: Sync> PortCell<T> {
312 fn check_cycle(&self, upstream_id: &PortId, downstream_id: &PortId) -> Result<(), AssemblyError> {
313 if (*self.downstreams.borrow()).contains_key(upstream_id) {
314 Err(AssemblyError(CyclicDependency(*upstream_id, *downstream_id)))
315 } else {
316 Ok(())
317 }
318 }
319
320 fn set_upstream(&self, new_binding: &Rc<PortCell<T>>) {
322 for cell_rc in (*self.downstreams.borrow()).values() {
323 cfg_if! {
324 if #[cfg(feature = "no-unsafe")] {
325 let mut ref_mut = cell_rc.borrow_mut();
326 *ref_mut.deref_mut() = Rc::clone(new_binding);
327 } else {
328 unsafe {
329 *cell_rc.get() = Rc::clone(new_binding);
330 }
331 }
332 }
333 }
334 }
335}
336
337impl<T: Sync> Default for PortCell<T> {
338 fn default() -> Self {
339 PortCell {
340 value: Default::default(),
341 downstreams: Default::default(),
342 }
343 }
344}
345
346pub struct Multiport<T: Sync> {
349 ports: Vec<Port<T>>,
350 id: TriggerId,
351}
352
353impl<T: Sync> Multiport<T> {
354 #[inline(always)]
356 pub(crate) fn new(ports: Vec<Port<T>>, id: TriggerId) -> Self {
357 Self { ports, id }
358 }
359
360 #[inline(always)]
362 pub fn len(&self) -> usize {
363 self.ports.len()
364 }
365
366 #[inline(always)]
368 pub fn is_empty(&self) -> bool {
369 self.ports.is_empty()
370 }
371
372 #[inline(always)]
374 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Port<T>> {
375 self.ports.iter_mut()
376 }
377
378 #[inline(always)]
381 pub fn iter(&self) -> impl Iterator<Item = &Port<T>> {
382 self.into_iter()
383 }
384
385 pub fn enumerate_set(&self) -> impl Iterator<Item = (usize, &Port<T>)> {
388 self.iter().enumerate().filter(|&(_, p)| p.is_present_now())
389 }
390
391 pub fn iterate_set(&self) -> impl Iterator<Item = &Port<T>> {
395 self.iter().filter(|&p| p.is_present_now())
396 }
397
398 pub fn iterate_values(&self) -> impl Iterator<Item = T> + '_
403 where
404 T: Copy,
405 {
406 self.iter().filter_map(|p| p.get())
407 }
408
409 #[cfg(not(feature = "no-unsafe"))]
414 pub fn iterate_values_ref(&self) -> impl Iterator<Item = &T> + '_ {
415 self.iter().filter_map(|p| p.get_ref())
416 }
417
418 pub fn enumerate_values(&self) -> impl Iterator<Item = (usize, T)> + '_
421 where
422 T: Copy,
423 {
424 self.iter().enumerate().filter_map(|(i, p)| p.get().map(|v| (i, v)))
425 }
426
427 #[cfg(not(feature = "no-unsafe"))]
430 pub fn enumerate_values_ref(&self) -> impl Iterator<Item = (usize, &T)> + '_ {
431 self.iter().enumerate().filter_map(|(i, p)| p.get_ref().map(|v| (i, v)))
432 }
433}
434
435impl<T: Sync> TriggerLike for Multiport<T> {
436 fn get_id(&self) -> TriggerId {
437 self.id
438 }
439}
440
441impl<'a, T: Sync> IntoIterator for &'a mut Multiport<T> {
442 type Item = &'a mut Port<T>;
443 type IntoIter = std::slice::IterMut<'a, Port<T>>;
444
445 fn into_iter(self) -> Self::IntoIter {
446 self.ports.iter_mut()
447 }
448}
449
450impl<'a, T: Sync> IntoIterator for &'a Multiport<T> {
451 type Item = &'a Port<T>;
452 type IntoIter = std::slice::Iter<'a, Port<T>>;
453
454 fn into_iter(self) -> Self::IntoIter {
455 self.ports.iter()
456 }
457}
458
459impl<T: Sync> Index<usize> for Multiport<T> {
460 type Output = Port<T>;
461
462 fn index(&self, index: usize) -> &Self::Output {
463 &self.ports[index]
464 }
465}
466
467impl<T: Sync> IndexMut<usize> for Multiport<T> {
468 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
469 &mut self.ports[index]
470 }
471}