-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a way to mark things that can only be done on the main thread #27
Comments
More ideas for how we can ensure something is only accessed on the main thread (e.g. after giving it to // Or ThisThreadOnly, ThreadLocked or something
struct MainThreadOnly<T>(T);
impl<T> !Send for MainThreadOnly<T> {}
impl<T> !Sync for MainThreadOnly<T> {}
// Allows
// `&'a MainThreadOnly<T>`
// -> `&'a T` (may be Sync)
impl<T> Deref for MainThreadOnly<T> { ... }
impl NSApplication {
fn set_main_menu(&self, menu: Id<NSMenu, Owned>) -> Id<MainThreadOnly<NSMenu>, Shared>;
} |
A big difficulty here lies in the interior-mutability nature of what we're trying to do; we'd like to be able to call mutating methods such as:
At some point in time where we only have access to I'll try draw some inspiration / knowledge from the |
A complicating factor is that if I change something from the main thread, e.g. on Note that |
The |
Reading Apple's docs again, they distinguish between Thread-Safe, Thread-Unsafe and Main Thread Only (likely written at some point after Mike Ash's article). Let's examine each of these in relation to Rust:
And everything is complicated by the fact that we'd like to share an object with another object, while still sometimes mutating it, so e.g. Oh, another thing: A lot of stuff in AppKit requires Cocoa to be in multithreading mode to even work on multiple threads, so we'll need a way to ensure that as well... |
Most mutation happens either through |
This functionality should live in |
I think the example in #27 (comment) is a bit of a different use-case, and I doubt it is safe to do in any way (once we have given The // Or ThisThreadOnly, ThreadLocked or something
#[repr(transparent)]
struct MainThreadOnly<T>(T);
// Creation methods
impl<T> MainThreadOnly<T> {
fn from_ref(obj: &T) -> &Self {
assert!(is_main_thread());
todo!()
}
fn from_mut(obj: &mut T) -> &mut Self {
assert!(is_main_thread());
todo!()
}
fn from_id<O: Ownership>(obj: Id<T, O>) -> Id<Self, O> {
assert!(is_main_thread());
todo!()
}
}
impl<T> !Send for MainThreadOnly<T> {}
impl<T> !Sync for MainThreadOnly<T> {}
// Allows giving to another thread and using the thread-safe APIs there
impl<T> Deref for MainThreadOnly<T> { ... }
// Thread-safe APIs (if any)
impl NSApplication {
// Note: Unsure if `+[NSApplication sharedApplication]` is even thread safe... This is just an example!
pub fn shared() -> Id<NSApplication, Shared>;
}
// Main thread only APIs
impl MainThreadOnly<NSApplication> {
pub fn set_main_menu(&self, menu: Id<NSMenu, Owned>) -> Id<MainThreadOnly<NSMenu>, Shared>;
}
// Safe because all non-thread-safe access is behind `MainThreadOnly<T>`
impl Send for NSApplication {}
impl Sync for NSApplication {} Which has the problem that the |
Regarding impl !Send for NSView {}
impl !Sync for NSView {}
impl NSView {
pub fn new(_: MainThreadMarker) -> Id<NSView, Owned> {
unsafe { msg_send_id![class!(NSView), new] }
}
// Doesn't need `MainThreadMarker`
pub fn has_marked_text(&self) -> bool {
unsafe { msg_send_bool![self, hasMarkedText] }
}
} This is only really viable for classes whose entire API requires the main thread, but maybe that is a common case? |
Many things on
NSApplication
(e.g.-run
, ...) require being done on the main thread; this is something we should clearly communicate in the type system!See the
winit
code for more examples of where it's required (NSWindow
, ...).See also the following links:
Idea:
The text was updated successfully, but these errors were encountered: