From 01d45a836f7c3485f353a8c171c0762730845de9 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 17 Nov 2023 06:20:20 -0800 Subject: [PATCH] Fixing Gooey compilation on MacOS After trying to run Gooey again on my Mac for the first time in a few weeks, I found that I ran into the Condvar issue again. Rather than pasting AssertUnwindSafe in those files, I've both reported the discrepency in unwind safety (rust-lang/rust#118009) and moved the workaround into a type that only uses AssertUnwindsafe when compiling for Apple. --- src/animation.rs | 6 +++--- src/tick.rs | 8 ++++---- src/utils.rs | 33 ++++++++++++++++++++++++++++++++- src/value.rs | 12 ++++-------- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/animation.rs b/src/animation.rs index 1200daed4..51c46d186 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -44,7 +44,7 @@ use std::fmt::{Debug, Display}; use std::ops::{ControlFlow, Deref, Div, Mul}; use std::panic::{RefUnwindSafe, UnwindSafe}; use std::str::FromStr; -use std::sync::{Arc, Condvar, Mutex, MutexGuard, OnceLock}; +use std::sync::{Arc, Mutex, MutexGuard, OnceLock}; use std::thread; use std::time::{Duration, Instant}; @@ -57,11 +57,11 @@ use kludgine::Color; use crate::animation::easings::Linear; use crate::styles::{Component, RequireInvalidation}; -use crate::utils::IgnorePoison; +use crate::utils::{IgnorePoison, UnwindsafeCondvar}; use crate::value::Dynamic; static ANIMATIONS: Mutex = Mutex::new(Animating::new()); -static NEW_ANIMATIONS: Condvar = Condvar::new(); +static NEW_ANIMATIONS: UnwindsafeCondvar = UnwindsafeCondvar::new(); fn thread_state() -> MutexGuard<'static, Animating> { static THREAD: OnceLock<()> = OnceLock::new(); diff --git a/src/tick.rs b/src/tick.rs index ad3f6c778..84db6452e 100644 --- a/src/tick.rs +++ b/src/tick.rs @@ -1,13 +1,13 @@ use std::collections::HashSet; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Condvar, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex, MutexGuard}; use std::time::{Duration, Instant}; use kludgine::app::winit::event::KeyEvent; use kludgine::app::winit::keyboard::Key; use crate::context::WidgetContext; -use crate::utils::IgnorePoison; +use crate::utils::{IgnorePoison, UnwindsafeCondvar}; use crate::value::Dynamic; use crate::widget::{EventHandling, HANDLED, IGNORED}; @@ -65,7 +65,7 @@ impl Tick { input: InputState::default(), }), period: tick_every, - sync: Condvar::new(), + sync: UnwindsafeCondvar::new(), rendered_frame: AtomicUsize::new(0), tick_number: Dynamic::default(), }); @@ -117,7 +117,7 @@ pub struct InputState { struct TickData { state: Mutex, period: Duration, - sync: Condvar, + sync: UnwindsafeCondvar, rendered_frame: AtomicUsize, tick_number: Dynamic, } diff --git a/src/utils.rs b/src/utils.rs index 228efa7d3..11ffd3989 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,9 +1,40 @@ use std::ops::Deref; -use std::sync::{OnceLock, PoisonError}; +use std::sync::{Condvar, OnceLock, PoisonError}; use kludgine::app::winit::event::Modifiers; use kludgine::app::winit::keyboard::ModifiersState; +/// This [`Condvar`] is a wrapper that on Mac OS/iOS asserts unwind safety. On +/// all other platforms, this is a transparent wrapper around `Condvar`. See +/// for more information. +#[derive(Debug, Default)] +pub struct UnwindsafeCondvar( + #[cfg(any(target_os = "ios", target_os = "macos"))] std::panic::AssertUnwindSafe, + #[cfg(not(any(target_os = "ios", target_os = "macos")))] Condvar, +); + +impl Deref for UnwindsafeCondvar { + type Target = Condvar; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl UnwindsafeCondvar { + pub const fn new() -> Self { + #[cfg(any(target_os = "ios", target_os = "macos"))] + { + Self(AssertUnwindSafe(Condvar::new())) + } + + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + { + Self(Condvar::new()) + } + } +} + /// Invokes the provided macro with a pattern that can be matched using this /// `macro_rules!` expression: `$($type:ident $field:tt $var:ident),+`, where `$type` is an /// identifier to use for the generic parameter and `$field` is the field index diff --git a/src/value.rs b/src/value.rs index 8dae32a20..52bfe472e 100644 --- a/src/value.rs +++ b/src/value.rs @@ -4,9 +4,8 @@ use std::cell::Cell; use std::fmt::{Debug, Display}; use std::future::Future; use std::ops::{Deref, DerefMut}; -use std::panic::AssertUnwindSafe; use std::str::FromStr; -use std::sync::{Arc, Condvar, Mutex, MutexGuard, TryLockError}; +use std::sync::{Arc, Mutex, MutexGuard, TryLockError}; use std::task::{Poll, Waker}; use std::thread::ThreadId; @@ -15,7 +14,7 @@ use intentional::Assert; use crate::animation::{DynamicTransition, LinearInterpolate}; use crate::context::{WidgetContext, WindowHandle}; -use crate::utils::{IgnorePoison, WithClone}; +use crate::utils::{IgnorePoison, UnwindsafeCondvar, WithClone}; use crate::widget::{WidgetId, WidgetInstance}; use crate::widgets::Switcher; @@ -40,7 +39,7 @@ impl Dynamic { widgets: AHashSet::new(), }), during_callback_state: Mutex::default(), - sync: AssertUnwindSafe(Condvar::new()), + sync: UnwindsafeCondvar::default(), })) } @@ -553,10 +552,7 @@ struct LockState { struct DynamicData { state: Mutex>, during_callback_state: Mutex>, - - // The AssertUnwindSafe is only needed on Mac. For some reason on - // Mac OS, Condvar isn't RefUnwindSafe. - sync: AssertUnwindSafe, + sync: UnwindsafeCondvar, } impl DynamicData {