1use extend::ext;
4use std::ops::{Deref, DerefMut};
5use void::{ResultVoidExt as _, Void};
6
7#[ext(name = PostageWatchSenderExt)]
15pub impl<T> postage::watch::Sender<T> {
16 fn try_maybe_send<F, E>(&mut self, update: F) -> Result<(), E>
21 where
22 T: PartialEq,
23 F: FnOnce(&T) -> Result<T, E>,
24 {
25 let lock = self.borrow();
26 let new = update(&*lock)?;
27 if new != *lock {
28 drop(lock);
33 *self.borrow_mut() = new;
34 }
35 Ok(())
36 }
37
38 fn maybe_send<F>(&mut self, update: F)
43 where
44 T: PartialEq,
45 F: FnOnce(&T) -> T,
46 {
47 self.try_maybe_send(|t| Ok::<_, Void>(update(t)))
48 .void_unwrap();
49 }
50}
51
52#[derive(Debug)]
53pub struct DropNotifyWatchSender<T: DropNotifyEofSignallable>(Option<postage::watch::Sender<T>>);
60
61pub trait DropNotifyEofSignallable {
65 fn eof() -> Self;
67
68 #[deprecated]
77 fn is_eof(&self) -> bool {
78 false
79 }
80}
81
82impl<T> DropNotifyEofSignallable for Option<T> {
83 fn eof() -> Self {
84 None
85 }
86
87 fn is_eof(&self) -> bool {
88 self.is_none()
89 }
90}
91
92impl<T: DropNotifyEofSignallable> DropNotifyWatchSender<T> {
93 pub fn new(inner: postage::watch::Sender<T>) -> Self {
95 DropNotifyWatchSender(Some(inner))
96 }
97
98 pub fn into_inner(mut self) -> postage::watch::Sender<T> {
100 self.0.take().expect("inner was None")
101 }
102}
103
104impl<T: DropNotifyEofSignallable> Deref for DropNotifyWatchSender<T> {
105 type Target = postage::watch::Sender<T>;
106 fn deref(&self) -> &Self::Target {
107 self.0.as_ref().expect("inner was None")
108 }
109}
110
111impl<T: DropNotifyEofSignallable> DerefMut for DropNotifyWatchSender<T> {
112 fn deref_mut(&mut self) -> &mut Self::Target {
113 self.0.as_mut().expect("inner was None")
114 }
115}
116
117impl<T: DropNotifyEofSignallable> Drop for DropNotifyWatchSender<T> {
118 fn drop(&mut self) {
119 if let Some(mut inner) = self.0.take() {
120 *inner.borrow_mut() = DropNotifyEofSignallable::eof();
122 }
123 }
124}
125
126#[cfg(test)]
127mod test {
128 #![allow(clippy::bool_assert_comparison)]
130 #![allow(clippy::clone_on_copy)]
131 #![allow(clippy::dbg_macro)]
132 #![allow(clippy::mixed_attributes_style)]
133 #![allow(clippy::print_stderr)]
134 #![allow(clippy::print_stdout)]
135 #![allow(clippy::single_char_pattern)]
136 #![allow(clippy::unwrap_used)]
137 #![allow(clippy::unchecked_time_subtraction)]
138 #![allow(clippy::useless_vec)]
139 #![allow(clippy::needless_pass_by_value)]
140 #![allow(clippy::string_slice)] use super::*;
144 use futures::select_biased;
145 use futures_await_test::async_test;
146
147 #[async_test]
148 async fn postage_sender_ext() {
149 use futures::FutureExt;
150 use futures::stream::StreamExt;
151
152 let (mut s, mut r) = postage::watch::channel_with(20);
153 select_biased! {
155 i = r.next().fuse() => assert_eq!(i, Some(20)),
156 _ = futures::future::ready(()) => { }, };
158 select_biased! {
160 _ = r.next().fuse() => panic!(),
161 _ = futures::future::ready(()) => { },
162 };
163
164 s.maybe_send(|i| *i);
165 select_biased! {
167 _ = r.next().fuse() => panic!(),
168 _ = futures::future::ready(()) => { },
169 };
170
171 s.maybe_send(|i| *i + 1);
172 select_biased! {
174 i = r.next().fuse() => assert_eq!(i, Some(21)),
175 _ = futures::future::ready(()) => panic!(),
176 };
177
178 let () = s.try_maybe_send(|_i| Err(())).unwrap_err();
179 select_biased! {
181 _ = r.next().fuse() => panic!(),
182 _ = futures::future::ready(()) => { },
183 };
184 }
185
186 #[test]
187 fn postage_drop() {
188 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
189 struct I(i32);
190
191 impl DropNotifyEofSignallable for I {
192 fn eof() -> I {
193 I(0)
194 }
195 fn is_eof(&self) -> bool {
196 self.0 == 0
197 }
198 }
199
200 let (s, r) = postage::watch::channel_with(I(20));
201 let s = DropNotifyWatchSender::new(s);
202
203 assert_eq!(*r.borrow(), I(20));
204 drop(s);
205 assert_eq!(*r.borrow(), I(0));
206
207 let (s, r) = postage::watch::channel_with(I(44));
208 let s = DropNotifyWatchSender::new(s);
209
210 assert_eq!(*r.borrow(), I(44));
211 drop(s.into_inner());
212 assert_eq!(*r.borrow(), I(44));
213 }
214}