LibCore: Add swift bindings for EventLoop as an Executor and Actor

This commit is contained in:
Andrew Kaster 2025-03-09 13:43:51 -06:00 committed by Andrew Kaster
commit c8787e6a9f
Notes: github-actions[bot] 2025-03-16 03:52:13 +00:00
10 changed files with 224 additions and 1 deletions

View file

@ -114,3 +114,20 @@ endif()
if (ANDROID)
target_link_libraries(LibCore PRIVATE log)
endif()
if (ENABLE_SWIFT)
set(SWIFT_EXCLUDE_HEADERS "SocketAddressWindows.h")
if(WIN32)
list(APPEND SWIFT_EXCLUDE_HEADERS "EventLoopImplementationUnix.h")
else()
list(APPEND SWIFT_EXCLUDE_HEADERS "EventLoopImplementationWindows.h")
endif()
generate_clang_module_map(LibCore EXCLUDE_FILES ${SWIFT_EXCLUDE_HEADERS})
target_sources(LibCore PRIVATE
EventSwift.mm
EventLoopExecutor.swift)
set_source_files_properties(EventSwift.mm PRIVATE PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(LibCore PRIVATE AK)
add_swift_target_properties(LibCore LAGOM_LIBRARIES AK)
endif()

View file

@ -12,6 +12,7 @@
#include <AK/Function.h>
#include <AK/Noncopyable.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/Swift.h>
#include <AK/Time.h>
#include <LibCore/Event.h>
#include <LibCore/Forward.h>
@ -40,6 +41,10 @@ class ThreadEventQueue;
// - Quit events, i.e. the event loop should exit.
// Any event that the event loop needs to wait on or needs to repeatedly handle is stored in a handle, e.g. s_timers.
class EventLoop {
AK_MAKE_NONMOVABLE(EventLoop);
AK_MAKE_NONCOPYABLE(EventLoop);
private:
friend struct EventLoopPusher;
public:
@ -90,7 +95,7 @@ public:
private:
NonnullOwnPtr<EventLoopImplementation> m_impl;
};
} SWIFT_UNSAFE_REFERENCE;
void deferred_invoke(ESCAPING Function<void()>);

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2025, Andrew Kaster <andrew@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
import AK
@_exported import CoreCxx
extension Core.EventLoop: Equatable {
func deferred_invoke(_ task: @escaping () -> Void) {
Core.deferred_invoke_block(self, task)
}
public static func == (lhs: Core.EventLoop, rhs: Core.EventLoop) -> Bool {
Unmanaged.passUnretained(lhs).toOpaque() == Unmanaged.passUnretained(rhs).toOpaque()
}
}
public class EventLoopExecutor: SerialExecutor, TaskExecutor, @unchecked Sendable {
nonisolated private let eventLoop: Core.EventLoop
public init() {
eventLoop = Core.EventLoop.current()
}
public init(eventLoop: Core.EventLoop) {
self.eventLoop = eventLoop
}
public nonisolated func enqueue(_ job: consuming ExecutorJob) {
let job = UnownedJob(job)
eventLoop.deferred_invoke { [self, job] in
job.runSynchronously(
isolatedTo: self.asUnownedSerialExecutor(),
taskExecutor: self.asUnownedTaskExecutor())
}
}
public func checkIsolated() {
precondition(Core.EventLoop.current() == eventLoop)
}
}
public protocol EventLoopActor: Actor {
nonisolated var executor: EventLoopExecutor { get } // impl with a let
}
extension EventLoopActor {
public nonisolated var unownedExecutor: UnownedSerialExecutor {
executor.asUnownedSerialExecutor()
}
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2025, Andrew Kaster <andrew@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibCore/Forward.h>
namespace Core {
void deferred_invoke_block(EventLoop& event_loop, void (^invokee)(void));
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2025, Andrew Kaster <andrew@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/EventLoop.h>
#include <LibCore/EventSwift.h>
#if !__has_feature(objc_arc)
# error "This file requires ARC"
#endif
namespace Core {
void deferred_invoke_block(EventLoop& event_loop, void (^invokee)(void))
{
event_loop.deferred_invoke([invokee = move(invokee)] {
invokee();
});
}
}