timely_communication/allocator/counters.rs
1//! Push and Pull wrappers to maintain counts of messages in channels.
2
3use std::rc::Rc;
4use std::cell::RefCell;
5use std::sync::mpsc::Sender;
6
7use crate::{Push, Pull};
8
9/// The push half of an intra-thread channel.
10pub struct Pusher<T, P: Push<T>> {
11 index: usize,
12 // count: usize,
13 events: Rc<RefCell<Vec<usize>>>,
14 pusher: P,
15 phantom: ::std::marker::PhantomData<T>,
16}
17
18impl<T, P: Push<T>> Pusher<T, P> {
19 /// Wraps a pusher with a message counter.
20 pub fn new(pusher: P, index: usize, events: Rc<RefCell<Vec<usize>>>) -> Self {
21 Pusher {
22 index,
23 // count: 0,
24 events,
25 pusher,
26 phantom: ::std::marker::PhantomData,
27 }
28 }
29}
30
31impl<T, P: Push<T>> Push<T> for Pusher<T, P> {
32 #[inline]
33 fn push(&mut self, element: &mut Option<T>) {
34 // if element.is_none() {
35 // if self.count != 0 {
36 // self.events
37 // .borrow_mut()
38 // .push_back(self.index);
39 // self.count = 0;
40 // }
41 // }
42 // else {
43 // self.count += 1;
44 // }
45 // TODO: Version above is less chatty, but can be a bit late in
46 // moving information along. Better, but needs cooperation.
47 // A `None` is a flush, and the wrapped pusher is unbuffered: nothing
48 // is enqueued, and so there is nothing to announce.
49 if element.is_some() {
50 self.events
51 .borrow_mut()
52 .push(self.index);
53 }
54
55 self.pusher.push(element)
56 }
57}
58
59/// The push half of an intra-thread channel.
60pub struct ArcPusher<T, P: Push<T>> {
61 index: usize,
62 // count: usize,
63 events: Sender<usize>,
64 pusher: P,
65 phantom: ::std::marker::PhantomData<T>,
66 buzzer: crate::buzzer::Buzzer,
67}
68
69impl<T, P: Push<T>> ArcPusher<T, P> {
70 /// Wraps a pusher with a message counter.
71 pub fn new(pusher: P, index: usize, events: Sender<usize>, buzzer: crate::buzzer::Buzzer) -> Self {
72 ArcPusher {
73 index,
74 // count: 0,
75 events,
76 pusher,
77 phantom: ::std::marker::PhantomData,
78 buzzer,
79 }
80 }
81}
82
83impl<T, P: Push<T>> Push<T> for ArcPusher<T, P> {
84 #[inline]
85 fn push(&mut self, element: &mut Option<T>) {
86 // if element.is_none() {
87 // if self.count != 0 {
88 // self.events
89 // .send((self.index, Event::Pushed(self.count)))
90 // .expect("Failed to send message count");
91 // self.count = 0;
92 // }
93 // }
94 // else {
95 // self.count += 1;
96 // }
97
98 // A `None` is a flush, and the wrapped pusher is unbuffered: nothing
99 // is enqueued, and so there is nothing to announce or to awaken for.
100 if element.is_none() { return; }
101
102 // These three calls should happen in this order, to ensure that
103 // we first enqueue data, second enqueue interest in the channel,
104 // and finally awaken the thread. Other orders are defective when
105 // multiple threads are involved.
106 self.pusher.push(element);
107 let _ = self.events.send(self.index);
108 // TODO : Perhaps this shouldn't be a fatal error (e.g. in shutdown).
109 // .expect("Failed to send message count");
110 self.buzzer.buzz();
111 }
112}
113
114/// The pull half of an intra-thread channel.
115pub struct Puller<T, P: Pull<T>> {
116 index: usize,
117 count: usize,
118 events: Rc<RefCell<Vec<usize>>>,
119 puller: P,
120 phantom: ::std::marker::PhantomData<T>,
121}
122
123impl<T, P: Pull<T>> Puller<T, P> {
124 /// Wraps a puller with a message counter.
125 pub fn new(puller: P, index: usize, events: Rc<RefCell<Vec<usize>>>) -> Self {
126 Puller {
127 index,
128 count: 0,
129 events,
130 puller,
131 phantom: ::std::marker::PhantomData,
132 }
133 }
134}
135impl<T, P: Pull<T>> Pull<T> for Puller<T, P> {
136 #[inline]
137 fn pull(&mut self) -> &mut Option<T> {
138 let result = self.puller.pull();
139 if result.is_none() {
140 if self.count != 0 {
141 self.events
142 .borrow_mut()
143 .push(self.index);
144 self.count = 0;
145 }
146 }
147 else {
148 self.count += 1;
149 }
150
151 result
152 }
153}