From 53f8a583dc9a54aaeae99e799bca0d11dd2ce626 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 19 Oct 2024 21:25:17 +0200 Subject: [PATCH] libluna+libos+libui: Move Action to libluna and make it usable in the kernel This commit adds an error-propagating constructor for Action and Function, which makes them usable in the kernel. --- gui/libui/include/ui/Button.h | 6 +- gui/libui/include/ui/Dialog.h | 4 +- gui/libui/include/ui/InputField.h | 6 +- gui/libui/include/ui/Window.h | 8 +- gui/libui/src/Button.cpp | 2 +- gui/libui/src/Dialog.cpp | 2 +- gui/libui/src/Window.cpp | 3 +- libluna/CMakeLists.txt | 2 +- libluna/include/luna/Action.h | 300 ++++++++++++++++++++++++++++++ libos/include/os/Action.h | 260 -------------------------- libos/include/os/EventLoop.h | 2 +- libos/include/os/IPC.h | 4 +- libos/include/os/Timer.h | 2 +- libos/src/IPC.cpp | 2 +- 14 files changed, 321 insertions(+), 282 deletions(-) create mode 100644 libluna/include/luna/Action.h delete mode 100644 libos/include/os/Action.h diff --git a/gui/libui/include/ui/Button.h b/gui/libui/include/ui/Button.h index 38d5f512..80c37639 100644 --- a/gui/libui/include/ui/Button.h +++ b/gui/libui/include/ui/Button.h @@ -8,7 +8,7 @@ */ #pragma once -#include +#include #include namespace ui @@ -19,7 +19,7 @@ namespace ui Button(Rect rect); void set_widget(Widget& widget); - void set_action(os::Action&& action); + void set_action(Action&& action); Result handle_mouse_move(Point position) override; Result handle_mouse_leave() override; @@ -32,6 +32,6 @@ namespace ui bool m_hovered { false }; bool m_clicked { false }; Widget* m_child; - os::Action m_action; + Action m_action; }; } diff --git a/gui/libui/include/ui/Dialog.h b/gui/libui/include/ui/Dialog.h index eb541dff..2c850c92 100644 --- a/gui/libui/include/ui/Dialog.h +++ b/gui/libui/include/ui/Dialog.h @@ -8,7 +8,7 @@ */ #pragma once -#include +#include #include namespace ui @@ -17,6 +17,6 @@ namespace ui { Result show_message(StringView title, StringView message); - Result show_input_dialog(StringView title, StringView message, os::Function callback); + Result show_input_dialog(StringView title, StringView message, Function callback); } } diff --git a/gui/libui/include/ui/InputField.h b/gui/libui/include/ui/InputField.h index ef09cf74..2f877ebe 100644 --- a/gui/libui/include/ui/InputField.h +++ b/gui/libui/include/ui/InputField.h @@ -8,7 +8,7 @@ */ #pragma once -#include +#include #include #include @@ -27,7 +27,7 @@ namespace ui StringView data(); - void on_submit(os::Function&& action) + void on_submit(Function&& action) { m_on_submit_action = move(action); m_has_on_submit_action = true; @@ -36,7 +36,7 @@ namespace ui private: SharedPtr m_font; - os::Function m_on_submit_action; + Function m_on_submit_action; bool m_has_on_submit_action { false }; }; } diff --git a/gui/libui/include/ui/Window.h b/gui/libui/include/ui/Window.h index ef6d4025..a0a37bba 100644 --- a/gui/libui/include/ui/Window.h +++ b/gui/libui/include/ui/Window.h @@ -73,14 +73,14 @@ namespace ui Result handle_mouse_buttons(ui::Point position, int buttons); Result handle_key_event(const ui::KeyEventRequest& request); - Result add_keyboard_shortcut(ui::Shortcut shortcut, bool intercept, os::Function&& action); + Result add_keyboard_shortcut(ui::Shortcut shortcut, bool intercept, Function&& action); int id() const { return m_id; } - void on_close(os::Action&& action) + void on_close(Action&& action) { m_on_close_action = move(action); m_has_on_close_action = true; @@ -99,13 +99,13 @@ namespace ui Option m_old_mouse_buttons; bool m_decorated { false }; - os::Action m_on_close_action; + Action m_on_close_action; bool m_has_on_close_action { false }; struct ShortcutAction { bool intercept; - os::Function action; + Function action; }; HashMap m_shortcuts; diff --git a/gui/libui/src/Button.cpp b/gui/libui/src/Button.cpp index 14e5ceb1..ab412cb1 100644 --- a/gui/libui/src/Button.cpp +++ b/gui/libui/src/Button.cpp @@ -24,7 +24,7 @@ namespace ui widget.set_parent(this); } - void Button::set_action(os::Action&& action) + void Button::set_action(Action&& action) { m_action = move(action); } diff --git a/gui/libui/src/Dialog.cpp b/gui/libui/src/Dialog.cpp index f3fc9af0..83d11a15 100644 --- a/gui/libui/src/Dialog.cpp +++ b/gui/libui/src/Dialog.cpp @@ -41,7 +41,7 @@ namespace ui::Dialog return {}; } - Result show_input_dialog(StringView title, StringView message, os::Function callback) + Result show_input_dialog(StringView title, StringView message, Function callback) { auto rect = ui::App::the().main_window()->canvas().rect(); int text_length = (int)message.length() * ui::Font::default_font()->width(); diff --git a/gui/libui/src/Window.cpp b/gui/libui/src/Window.cpp index 3aa699c6..f52a50c2 100644 --- a/gui/libui/src/Window.cpp +++ b/gui/libui/src/Window.cpp @@ -224,8 +224,7 @@ namespace ui return m_main_widget->handle_key_event(request); } - Result Window::add_keyboard_shortcut(ui::Shortcut shortcut, bool intercept, - os::Function&& action) + Result Window::add_keyboard_shortcut(ui::Shortcut shortcut, bool intercept, Function&& action) { TRY(m_shortcuts.try_set(shortcut, { intercept, move(action) })); diff --git a/libluna/CMakeLists.txt b/libluna/CMakeLists.txt index 5c2d3da6..86ff987a 100644 --- a/libluna/CMakeLists.txt +++ b/libluna/CMakeLists.txt @@ -40,7 +40,7 @@ set(SOURCES ) add_library(luna-freestanding ${FREESTANDING_SOURCES}) -target_compile_definitions(luna-freestanding PRIVATE USE_FREESTANDING) +target_compile_definitions(luna-freestanding PUBLIC USE_FREESTANDING) target_compile_options(luna-freestanding PRIVATE ${COMMON_FLAGS}) target_compile_options(luna-freestanding PRIVATE -nostdlib -mcmodel=kernel -ffreestanding) diff --git a/libluna/include/luna/Action.h b/libluna/include/luna/Action.h new file mode 100644 index 00000000..b1d0f6ad --- /dev/null +++ b/libluna/include/luna/Action.h @@ -0,0 +1,300 @@ +/** + * @file Action.h + * @author apio (cloudapio.eu) + * @brief Wrapper for callable objects, like function pointers or lambdas. + * + * @copyright Copyright (c) 2024, the Luna authors. + * + */ + +#pragma once +#include +#include + +/** + * @brief Wrapper for callable objects with no arguments. + * + * Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as + * arguments. The Action type acts as a callable wrapper for such functions, allowing them to be passed as arguments + * to any function. + */ +class Action +{ + public: + /** + * @brief Construct a new empty Action object. + * + * Since it is not wrapping any callable object, this object is invalid and attempting to invoke its + * (nonexistent) callable object will result in a crash at runtime. + */ + Action() + { + m_action = nullptr; + } + + /** + * @brief Construct a new Action object, moving it from another one. + * + * @param other The old Action object to move from. This object will become invalid. + */ + Action(Action&& other) : m_action(other.m_action) + { + other.m_action = {}; + } + + /** + * @brief Construct a new Action object, copying it from another one. + * + * @param other The old Action object to copy from. + */ + Action(Action& other) : m_action(other.m_action) + { + } + +#ifndef USE_FREESTANDING + /** + * @brief Construct a new Action object, copying it from another one. + * + * @param other The old Action object to copy from. + */ + Action(const Action& other) : m_action(other.m_action) + { + // FIXME: Doesn't actually copy? + } + + /** + * @brief Construct a new Action object from a callable object. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + */ + template Action(T&& function) + { + m_action = + adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl(move(function))).release_value(); + } + + /** + * @brief Assign a new callable object to this Action. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + * @return Action& A reference to this object, as required by operator=(). + */ + template Action& operator=(T&& function) + { + m_action = + adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl(move(function))).release_value(); + return *this; + } +#endif + + /** + * @brief Construct a new Action object, wrapping a callable object. This version propagates errors, and thus can + * be used in freestanding contexts, unlike the constructors above. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + */ + template static Result wrap(T&& function) + { + auto base = TRY(adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl(move(function)))); + return Action(base); + } + + /** + * @brief Call the underlying object. + */ + void operator()() + { + expect(m_action, "Action called with no underlying callable object"); + return m_action->call(); + } + + private: + class ActionBase : public Shareable + { + public: + virtual void call() = 0; + virtual ~ActionBase() = default; + }; + + template class ActionImpl final : public ActionBase + { + public: + ActionImpl(T&& function) : m_function(move(function)) + { + } + + void call() + { + m_function(); + } + + private: + T m_function; + }; + + Action(SharedPtr action) : m_action(action) + { + } + + SharedPtr m_action; +}; + +/** + * @brief Wrapper for callable objects. + * + * Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as + * arguments. The Function type acts as a callable wrapper for such functions, allowing them to be passed as + * arguments to any function. + */ +template class Function +{ + public: + /** + * @brief Construct a new empty Function object. + * + * Since it is not wrapping any callable object, this object is invalid and attempting to invoke its + * (nonexistent) callable object will result in a crash at runtime. + */ + Function() + { + m_action = nullptr; + } + + /** + * @brief Construct a new Function object, moving it from another one. + * + * @param other The old Function object to move from. This object will become invalid. + */ + Function(Function&& other) : m_action(other.m_action) + { + other.m_action = {}; + } + + /** + * @brief Construct a new Function object, copying it from another one. + * + * @param other The old Function object to copy from. + */ + Function(Function& other) : m_action(other.m_action) + { + } + +#ifndef USE_FREESTANDING + /** + * @brief Construct a new Function object, copying it from another one. + * + * @param other The old Function object to copy from. + */ + Function(const Function& other) : m_action(other.m_action) + { + // FIXME: Doesn't actually copy? + } + + /** + * @brief Construct a new Function object from a callable object. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + */ + template Function(T&& function) + { + m_action = + adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl(move(function))).release_value(); + } + + /** + * @brief Assign a new callable object to this Function. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + * @return Action& A reference to this object, as required by operator=(). + */ + template Function& operator=(T&& function) + { + m_action = + adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl(move(function))).release_value(); + return *this; + } + +#endif + + /** + * @brief Construct a new Function object, wrapping a callable object. This version propagates errors, and thus can + * be used in freestanding contexts, unlike the constructors above. + * + * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object + * doesn't actually need a type name. + * @param function The callable object to wrap. + */ + template static Result wrap(T&& function) + { + auto base = TRY(adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl(move(function)))); + return Function(base); + } + + /** + * @brief Call the underlying object. + */ + void operator()(Args... args) + { + expect(m_action, "Function called with no underlying callable object"); + return m_action->call(args...); + } + + /** + * @brief Call the underlying object. + */ + void operator()(Args... args) const + { + expect(m_action, "Function called with no underlying callable object"); + return m_action->call(args...); + } + + private: + class FunctionBase : public Shareable + { + public: + virtual void call(Args... args) = 0; + virtual void call(Args... args) const = 0; + virtual ~FunctionBase() = default; + }; + + template class FunctionImpl final : public FunctionBase + { + public: + FunctionImpl(FunctionImpl&& function) : m_function(move(function.m_function)) + { + } + + FunctionImpl(T&& function) : m_function(move(function)) + { + } + + void call(Args... args) override + { + m_function(args...); + } + + void call(Args... args) const override + { + m_function(args...); + } + + private: + T m_function; + }; + + Function(SharedPtr action) : m_action(action) + { + } + + SharedPtr m_action; +}; diff --git a/libos/include/os/Action.h b/libos/include/os/Action.h deleted file mode 100644 index 3896a4d1..00000000 --- a/libos/include/os/Action.h +++ /dev/null @@ -1,260 +0,0 @@ -/** - * @file Action.h - * @author apio (cloudapio.eu) - * @brief Wrapper for callable objects, like function pointers or lambdas. - * - * @copyright Copyright (c) 2023, the Luna authors. - * - */ - -#pragma once -#include -#include - -namespace os -{ - /** - * @brief Wrapper for callable objects with no arguments. - * - * Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as - * arguments. The Action type acts as a callable wrapper for such functions, allowing them to be passed as arguments - * to any function. - */ - class Action - { - public: - /** - * @brief Construct a new empty Action object. - * - * Since it is not wrapping any callable object, this object is invalid and attempting to invoke its - * (nonexistent) callable object will result in a crash at runtime. - */ - Action() - { - m_action = nullptr; - } - - /** - * @brief Construct a new Action object, moving it from another one. - * - * @param other The old Action object to move from. This object will become invalid. - */ - Action(Action&& other) : m_action(other.m_action) - { - other.m_action = {}; - } - - /** - * @brief Construct a new Action object, copying it from another one. - * - * @param other The old Action object to copy from. - */ - Action(Action& other) : m_action(other.m_action) - { - } - - /** - * @brief Construct a new Action object, copying it from another one. - * - * @param other The old Action object to copy from. - */ - Action(const Action& other) : m_action(other.m_action) - { - } - - /** - * @brief Construct a new Action object from a callable object. - * - * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object - * doesn't actually need a type name. - * @param function The callable object to wrap. - */ - template Action(T&& function) - { - m_action = - adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl(move(function))).release_value(); - } - - /** - * @brief Assign a new callable object to this Action. - * - * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object - * doesn't actually need a type name. - * @param function The callable object to wrap. - * @return Action& A reference to this object, as required by operator=(). - */ - template Action& operator=(T&& function) - { - m_action = - adopt_shared_if_nonnull((ActionBase*)new (std::nothrow) ActionImpl(move(function))).release_value(); - return *this; - } - - /** - * @brief Call the underlying object. - */ - void operator()() - { - expect(m_action, "os::Action called with no underlying callable object"); - return m_action->call(); - } - - private: - class ActionBase : public Shareable - { - public: - virtual void call() = 0; - virtual ~ActionBase() = default; - }; - - template class ActionImpl final : public ActionBase - { - public: - ActionImpl(T&& function) : m_function(move(function)) - { - } - - void call() - { - m_function(); - } - - private: - T m_function; - }; - - SharedPtr m_action; - }; - - /** - * @brief Wrapper for callable objects. - * - * Certain callable types such as capture lambdas don't have a named type, thus they can't be passed to functions as - * arguments. The Function type acts as a callable wrapper for such functions, allowing them to be passed as - * arguments to any function. - */ - template class Function - { - public: - /** - * @brief Construct a new empty Function object. - * - * Since it is not wrapping any callable object, this object is invalid and attempting to invoke its - * (nonexistent) callable object will result in a crash at runtime. - */ - Function() - { - m_action = nullptr; - } - - /** - * @brief Construct a new Function object, moving it from another one. - * - * @param other The old Function object to move from. This object will become invalid. - */ - Function(Function&& other) : m_action(other.m_action) - { - other.m_action = {}; - } - - /** - * @brief Construct a new Function object, copying it from another one. - * - * @param other The old Function object to copy from. - */ - Function(Function& other) : m_action(other.m_action) - { - } - - /** - * @brief Construct a new Function object, copying it from another one. - * - * @param other The old Function object to copy from. - */ - Function(const Function& other) : m_action(other.m_action) - { - } - - /** - * @brief Construct a new Function object from a callable object. - * - * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object - * doesn't actually need a type name. - * @param function The callable object to wrap. - */ - template Function(T&& function) - { - m_action = adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl(move(function))) - .release_value(); - } - - /** - * @brief Assign a new callable object to this Function. - * - * @tparam T The type of the callable object. Since this can be guessed by template deduction, the object - * doesn't actually need a type name. - * @param function The callable object to wrap. - * @return Action& A reference to this object, as required by operator=(). - */ - template Function& operator=(T&& function) - { - m_action = adopt_shared_if_nonnull((FunctionBase*)new (std::nothrow) FunctionImpl(move(function))) - .release_value(); - return *this; - } - - /** - * @brief Call the underlying object. - */ - void operator()(Args... args) - { - expect(m_action, "os::Function called with no underlying callable object"); - return m_action->call(args...); - } - - /** - * @brief Call the underlying object. - */ - void operator()(Args... args) const - { - expect(m_action, "os::Function called with no underlying callable object"); - return m_action->call(args...); - } - - private: - class FunctionBase : public Shareable - { - public: - virtual void call(Args... args) = 0; - virtual void call(Args... args) const = 0; - virtual ~FunctionBase() = default; - }; - - template class FunctionImpl final : public FunctionBase - { - public: - FunctionImpl(FunctionImpl&& function) : m_function(move(function.m_function)) - { - } - - FunctionImpl(T&& function) : m_function(move(function)) - { - } - - void call(Args... args) override - { - m_function(args...); - } - - void call(Args... args) const override - { - m_function(args...); - } - - private: - T m_function; - }; - - SharedPtr m_action; - }; -} diff --git a/libos/include/os/EventLoop.h b/libos/include/os/EventLoop.h index d8ddcaa8..29ed7310 100644 --- a/libos/include/os/EventLoop.h +++ b/libos/include/os/EventLoop.h @@ -8,9 +8,9 @@ */ #pragma once +#include #include #include -#include #include #include diff --git a/libos/include/os/IPC.h b/libos/include/os/IPC.h index 5385a4a6..028780bf 100644 --- a/libos/include/os/IPC.h +++ b/libos/include/os/IPC.h @@ -8,7 +8,7 @@ */ #pragma once -#include +#include #include #include @@ -382,7 +382,7 @@ namespace os * @return true The child is ready. * @return false The method timed out. */ - static bool run_and_wait(os::Action&& action, int timeout = -1); + static bool run_and_wait(Action&& action, int timeout = -1); }; /** diff --git a/libos/include/os/Timer.h b/libos/include/os/Timer.h index 9a97087b..ee245b1e 100644 --- a/libos/include/os/Timer.h +++ b/libos/include/os/Timer.h @@ -8,9 +8,9 @@ */ #pragma once +#include #include #include -#include #include namespace os diff --git a/libos/src/IPC.cpp b/libos/src/IPC.cpp index bba6602e..740a152c 100644 --- a/libos/src/IPC.cpp +++ b/libos/src/IPC.cpp @@ -124,7 +124,7 @@ namespace os::IPC return result > 0; } - bool Notifier::run_and_wait(os::Action&& action, int timeout) + bool Notifier::run_and_wait(Action&& action, int timeout) { auto notifier = create(); notifier.hook();