Assert zero-sized closures in Subscription at compile-time
This commit is contained in:
parent
c566845091
commit
92ecc18318
1 changed files with 26 additions and 16 deletions
|
|
@ -299,20 +299,14 @@ impl<T> Subscription<T> {
|
||||||
|
|
||||||
/// Transforms the [`Subscription`] output with the given function.
|
/// Transforms the [`Subscription`] output with the given function.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// The closure provided must be a non-capturing closure.
|
||||||
/// The closure provided must be a non-capturing closure. The method
|
|
||||||
/// will panic in debug mode otherwise.
|
|
||||||
pub fn map<F, A>(self, f: F) -> Subscription<A>
|
pub fn map<F, A>(self, f: F) -> Subscription<A>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
F: Fn(T) -> A + MaybeSend + Clone + 'static,
|
F: Fn(T) -> A + MaybeSend + Clone + 'static,
|
||||||
A: 'static,
|
A: 'static,
|
||||||
{
|
{
|
||||||
debug_assert!(
|
F::assert_zero_size();
|
||||||
std::mem::size_of::<F>() == 0,
|
|
||||||
"the closure {} provided in `Subscription::map` is capturing",
|
|
||||||
std::any::type_name::<F>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
struct Map<A, B, F>
|
struct Map<A, B, F>
|
||||||
where
|
where
|
||||||
|
|
@ -362,20 +356,14 @@ impl<T> Subscription<T> {
|
||||||
/// Transforms the [`Subscription`] output with the given function, yielding only
|
/// Transforms the [`Subscription`] output with the given function, yielding only
|
||||||
/// values only when the function returns `Some(A)`.
|
/// values only when the function returns `Some(A)`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// The closure provided must be a non-capturing closure.
|
||||||
/// The closure provided must be a non-capturing closure. The method
|
|
||||||
/// will panic in debug mode otherwise.
|
|
||||||
pub fn filter_map<F, A>(mut self, f: F) -> Subscription<A>
|
pub fn filter_map<F, A>(mut self, f: F) -> Subscription<A>
|
||||||
where
|
where
|
||||||
T: MaybeSend + 'static,
|
T: MaybeSend + 'static,
|
||||||
F: Fn(T) -> Option<A> + MaybeSend + Clone + 'static,
|
F: Fn(T) -> Option<A> + MaybeSend + Clone + 'static,
|
||||||
A: MaybeSend + 'static,
|
A: MaybeSend + 'static,
|
||||||
{
|
{
|
||||||
debug_assert!(
|
F::assert_zero_size();
|
||||||
std::mem::size_of::<F>() == 0,
|
|
||||||
"the closure {} provided in `Subscription::filter_map` is capturing",
|
|
||||||
std::any::type_name::<F>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
struct FilterMap<A, B, F>
|
struct FilterMap<A, B, F>
|
||||||
where
|
where
|
||||||
|
|
@ -533,3 +521,25 @@ where
|
||||||
crate::boxed_stream((self.spawn)(&self.data, input))
|
crate::boxed_stream((self.spawn)(&self.data, input))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait PanicWhenNotZeroSized: Sized {
|
||||||
|
const _CHECK: () = check_zero_sized::<Self>();
|
||||||
|
|
||||||
|
#[allow(path_statements, clippy::no_effect)]
|
||||||
|
fn assert_zero_size() {
|
||||||
|
<Self as PanicWhenNotZeroSized>::_CHECK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PanicWhenNotZeroSized for T {}
|
||||||
|
|
||||||
|
const fn check_zero_sized<T>() {
|
||||||
|
if std::mem::size_of::<T>() != 0 {
|
||||||
|
panic!(
|
||||||
|
"The Subscription closure provided is not non-capturing. \
|
||||||
|
Closures given to Subscription::map or filter_map cannot \
|
||||||
|
capture external variables. If you need to capture state, \
|
||||||
|
consider using Subscription::with."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue