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.
This commit is contained in:
Jonathan Johnson 2023-11-17 06:20:20 -08:00
parent c39f8f33ad
commit 01d45a836f
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
4 changed files with 43 additions and 16 deletions

View file

@ -44,7 +44,7 @@ use std::fmt::{Debug, Display};
use std::ops::{ControlFlow, Deref, Div, Mul}; use std::ops::{ControlFlow, Deref, Div, Mul};
use std::panic::{RefUnwindSafe, UnwindSafe}; use std::panic::{RefUnwindSafe, UnwindSafe};
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Condvar, Mutex, MutexGuard, OnceLock}; use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -57,11 +57,11 @@ use kludgine::Color;
use crate::animation::easings::Linear; use crate::animation::easings::Linear;
use crate::styles::{Component, RequireInvalidation}; use crate::styles::{Component, RequireInvalidation};
use crate::utils::IgnorePoison; use crate::utils::{IgnorePoison, UnwindsafeCondvar};
use crate::value::Dynamic; use crate::value::Dynamic;
static ANIMATIONS: Mutex<Animating> = Mutex::new(Animating::new()); static ANIMATIONS: Mutex<Animating> = Mutex::new(Animating::new());
static NEW_ANIMATIONS: Condvar = Condvar::new(); static NEW_ANIMATIONS: UnwindsafeCondvar = UnwindsafeCondvar::new();
fn thread_state() -> MutexGuard<'static, Animating> { fn thread_state() -> MutexGuard<'static, Animating> {
static THREAD: OnceLock<()> = OnceLock::new(); static THREAD: OnceLock<()> = OnceLock::new();

View file

@ -1,13 +1,13 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::atomic::{AtomicUsize, Ordering}; 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 std::time::{Duration, Instant};
use kludgine::app::winit::event::KeyEvent; use kludgine::app::winit::event::KeyEvent;
use kludgine::app::winit::keyboard::Key; use kludgine::app::winit::keyboard::Key;
use crate::context::WidgetContext; use crate::context::WidgetContext;
use crate::utils::IgnorePoison; use crate::utils::{IgnorePoison, UnwindsafeCondvar};
use crate::value::Dynamic; use crate::value::Dynamic;
use crate::widget::{EventHandling, HANDLED, IGNORED}; use crate::widget::{EventHandling, HANDLED, IGNORED};
@ -65,7 +65,7 @@ impl Tick {
input: InputState::default(), input: InputState::default(),
}), }),
period: tick_every, period: tick_every,
sync: Condvar::new(), sync: UnwindsafeCondvar::new(),
rendered_frame: AtomicUsize::new(0), rendered_frame: AtomicUsize::new(0),
tick_number: Dynamic::default(), tick_number: Dynamic::default(),
}); });
@ -117,7 +117,7 @@ pub struct InputState {
struct TickData { struct TickData {
state: Mutex<TickState>, state: Mutex<TickState>,
period: Duration, period: Duration,
sync: Condvar, sync: UnwindsafeCondvar,
rendered_frame: AtomicUsize, rendered_frame: AtomicUsize,
tick_number: Dynamic<u64>, tick_number: Dynamic<u64>,
} }

View file

@ -1,9 +1,40 @@
use std::ops::Deref; 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::event::Modifiers;
use kludgine::app::winit::keyboard::ModifiersState; 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
/// <https://github.com/rust-lang/rust/issues/118009> for more information.
#[derive(Debug, Default)]
pub struct UnwindsafeCondvar(
#[cfg(any(target_os = "ios", target_os = "macos"))] std::panic::AssertUnwindSafe<Condvar>,
#[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 /// 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 /// `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 /// identifier to use for the generic parameter and `$field` is the field index

View file

@ -4,9 +4,8 @@ use std::cell::Cell;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::future::Future; use std::future::Future;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::panic::AssertUnwindSafe;
use std::str::FromStr; 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::task::{Poll, Waker};
use std::thread::ThreadId; use std::thread::ThreadId;
@ -15,7 +14,7 @@ use intentional::Assert;
use crate::animation::{DynamicTransition, LinearInterpolate}; use crate::animation::{DynamicTransition, LinearInterpolate};
use crate::context::{WidgetContext, WindowHandle}; use crate::context::{WidgetContext, WindowHandle};
use crate::utils::{IgnorePoison, WithClone}; use crate::utils::{IgnorePoison, UnwindsafeCondvar, WithClone};
use crate::widget::{WidgetId, WidgetInstance}; use crate::widget::{WidgetId, WidgetInstance};
use crate::widgets::Switcher; use crate::widgets::Switcher;
@ -40,7 +39,7 @@ impl<T> Dynamic<T> {
widgets: AHashSet::new(), widgets: AHashSet::new(),
}), }),
during_callback_state: Mutex::default(), during_callback_state: Mutex::default(),
sync: AssertUnwindSafe(Condvar::new()), sync: UnwindsafeCondvar::default(),
})) }))
} }
@ -553,10 +552,7 @@ struct LockState {
struct DynamicData<T> { struct DynamicData<T> {
state: Mutex<State<T>>, state: Mutex<State<T>>,
during_callback_state: Mutex<Option<LockState>>, during_callback_state: Mutex<Option<LockState>>,
sync: UnwindsafeCondvar,
// The AssertUnwindSafe is only needed on Mac. For some reason on
// Mac OS, Condvar isn't RefUnwindSafe.
sync: AssertUnwindSafe<Condvar>,
} }
impl<T> DynamicData<T> { impl<T> DynamicData<T> {