From f39a5fd8953494fd8e41c05bc053519740d09612 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 5 Feb 2024 00:15:35 +0100 Subject: Use `TypeId` to identify `subscription::Map` --- futures/src/subscription.rs | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 7163248d..4d5a1192 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -10,6 +10,7 @@ use crate::{BoxStream, MaybeSend}; use futures::channel::mpsc; use futures::never::Never; +use std::any::TypeId; use std::hash::Hash; /// A stream of runtime events. @@ -88,7 +89,10 @@ impl Subscription { } /// Transforms the [`Subscription`] output with the given function. - pub fn map(mut self, f: fn(Message) -> A) -> Subscription + pub fn map( + mut self, + f: impl Fn(Message) -> A + MaybeSend + Clone + 'static, + ) -> Subscription where Message: 'static, A: 'static, @@ -97,8 +101,9 @@ impl Subscription { recipes: self .recipes .drain(..) - .map(|recipe| { - Box::new(Map::new(recipe, f)) as Box> + .map(move |recipe| { + Box::new(Map::new(recipe, f.clone())) + as Box> }) .collect(), } @@ -143,27 +148,39 @@ pub trait Recipe { fn stream(self: Box, input: EventStream) -> BoxStream; } -struct Map { +struct Map +where + F: Fn(A) -> B + 'static, +{ + id: TypeId, recipe: Box>, - mapper: fn(A) -> B, + mapper: F, } -impl Map { - fn new(recipe: Box>, mapper: fn(A) -> B) -> Self { - Map { recipe, mapper } +impl Map +where + F: Fn(A) -> B + 'static, +{ + fn new(recipe: Box>, mapper: F) -> Self { + Map { + id: TypeId::of::(), + recipe, + mapper, + } } } -impl Recipe for Map +impl Recipe for Map where A: 'static, B: 'static, + F: Fn(A) -> B + 'static + MaybeSend, { type Output = B; fn hash(&self, state: &mut Hasher) { + self.id.hash(state); self.recipe.hash(state); - self.mapper.hash(state); } fn stream(self: Box, input: EventStream) -> BoxStream { -- cgit From 2470a3fb40c08b0017d47e7e5a4e8e7255f65919 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 5 Feb 2024 21:34:35 +0100 Subject: Assert closure provided to `Subscription::map` is non-capturing --- futures/src/subscription.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 4d5a1192..1ee291c1 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -89,14 +89,22 @@ impl Subscription { } /// Transforms the [`Subscription`] output with the given function. - pub fn map( - mut self, - f: impl Fn(Message) -> A + MaybeSend + Clone + 'static, - ) -> Subscription + /// + /// # Panics + /// The closure provided must be a non-capturing closure. The method + /// will panic in debug mode otherwise. + pub fn map(mut self, f: F) -> Subscription where Message: 'static, + F: Fn(Message) -> A + MaybeSend + Clone + 'static, A: 'static, { + debug_assert!( + std::mem::size_of::() == 0, + "the closure {} provided in `Subscription::map` is capturing", + std::any::type_name::(), + ); + Subscription { recipes: self .recipes -- cgit From 35bbee501fc1ab97c89d72472ad3cee59346601c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 5 Feb 2024 21:37:13 +0100 Subject: Update `CHANGELOG` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bd1cf2a..0d16cece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `size_hint` not being called from `element::Map`. [#2224](https://github.com/iced-rs/iced/pull/2224) - `size_hint` not being called from `element::Explain`. [#2225](https://github.com/iced-rs/iced/pull/2225) - Slow touch scrolling for `TextEditor` widget. [#2140](https://github.com/iced-rs/iced/pull/2140) +- `Subscription::map` using unreliable function pointer hash to identify mappers. [#2237](https://github.com/iced-rs/iced/pull/2237) Many thanks to... -- cgit From 2fb271a9764f2dd6f029ddab69beb04dc2749b70 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 5 Feb 2024 21:39:03 +0100 Subject: Remove redundant `id` field in `subscription::Map` --- futures/src/subscription.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 1ee291c1..e32227f6 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -160,7 +160,6 @@ struct Map where F: Fn(A) -> B + 'static, { - id: TypeId, recipe: Box>, mapper: F, } @@ -170,11 +169,7 @@ where F: Fn(A) -> B + 'static, { fn new(recipe: Box>, mapper: F) -> Self { - Map { - id: TypeId::of::(), - recipe, - mapper, - } + Map { recipe, mapper } } } @@ -187,7 +182,7 @@ where type Output = B; fn hash(&self, state: &mut Hasher) { - self.id.hash(state); + TypeId::of::().hash(state); self.recipe.hash(state); } -- cgit