Skip to content
This repository was archived by the owner on Oct 2, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ endif()
set(_XAML_TARGETS
xaml_global
xaml_meta xaml_markup
xaml_async
xaml_ui xaml_ui_appmain
)

Expand Down Expand Up @@ -226,6 +227,7 @@ xaml_fix_char8_t_flags()
add_subdirectory(global)
add_subdirectory(helpers)
add_subdirectory(meta)
add_subdirectory(async)
add_subdirectory(markup)
add_subdirectory(ui)
if(${BUILD_PARSER})
Expand Down
27 changes: 27 additions & 0 deletions async/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
project(XamlAsync CXX)

file(GLOB ASYNC_HEADERS "include/xaml/async/*.h")
file(GLOB ASYNC_SOURCE "src/*.cpp")
add_library(xaml_async ${ASYNC_SOURCE})

target_include_directories(xaml_async
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
)

target_link_libraries(xaml_async PUBLIC xaml_global xaml_meta)

if(${BUILD_SHARED_LIBS})
target_compile_definitions(xaml_async PRIVATE "XAML_ASYNC_API=__XAML_EXPORT")
endif()

if(${XAML_INSTALL})
install(FILES ${ASYNC_HEADERS} DESTINATION include/xaml)
endif()

if(${BUILD_TESTS})
add_subdirectory(test)
endif()
188 changes: 188 additions & 0 deletions async/include/xaml/async/action.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#ifndef XAML_ASYNC_ACTION_H
#define XAML_ASYNC_ACTION_H

#include <xaml/async/info.h>
#include <xaml/delegate.h>
#include <xaml/meta/meta_macros.h>
#include <xaml/vector.h>

#ifdef __cplusplus
#include <atomic>
#include <coroutine>
#include <xaml/ptr.hpp>
#endif // __cplusplus

XAML_CLASS(xaml_async_action, { 0xe31c7f48, 0x8af4, 0x46af, { 0xac, 0x54, 0x01, 0xa1, 0xc1, 0xea, 0xea, 0x1e } })

#ifndef xaml_delegate_2__xaml_async_action__xaml_async_status_defined
#define xaml_delegate_2__xaml_async_action__xaml_async_status_defined
XAML_DELEGATE_2_TYPE(XAML_T_O(xaml_async_action), XAML_T_V(xaml_async_status))
#endif // !xaml_delegate_2__xaml_async_action__xaml_async_status_defined

#define XAML_ASYNC_ACTION_VTBL(type) \
XAML_VTBL_INHERIT(XAML_ASYNC_INFO_VTBL(type)); \
XAML_PROP(completed, type, XAML_DELEGATE_2_NAME(xaml_async_action, xaml_async_status)**, XAML_DELEGATE_2_NAME(xaml_async_action, xaml_async_status)*)

XAML_DECL_INTERFACE_(xaml_async_action, xaml_async_info)
{
XAML_DECL_VTBL(xaml_async_action, XAML_ASYNC_ACTION_VTBL);
};

#ifndef xaml_enumerator_1__xaml_async_action_defined
#define xaml_enumerator_1__xaml_async_action_defined
XAML_ENUMERATOR_1_TYPE(XAML_T_O(xaml_async_action))
#endif // !xaml_enumerator_1__xaml_async_action_defined

#ifndef xaml_vector_view_1__xaml_async_action_defined
#define xaml_vector_view_1__xaml_async_action_defined
XAML_VECTOR_VIEW_1_TYPE(XAML_T_O(xaml_async_action))
#endif // !xaml_vector_view_1__xaml_async_action_defined

EXTERN_C XAML_ASYNC_API xaml_result XAML_CALL xaml_async_action_wait_all(XAML_VECTOR_VIEW_1_NAME(xaml_async_action) *) XAML_NOEXCEPT;

#ifdef __cplusplus
template <typename T, typename I>
struct xaml_async_promise_base : xaml_implement<T, I>
{
std::exception_ptr m_exception{};
std::atomic<xaml_async_status> m_status{};
xaml_ptr<xaml_delegate<I, xaml_async_status>> m_handler{};

std::coroutine_handle<T> get_handle() { return std::coroutine_handle<T>::from_promise(*static_cast<T*>(this)); }

std::uint32_t XAML_CALL release() noexcept override
{
std::int32_t res = --this->m_ref_count;
if (res == 0)
{
get_handle().destroy();
}
return res;
}

xaml_result XAML_CALL get_completed(xaml_delegate<I, xaml_async_status>** ptr) noexcept override
{
return m_handler.query(ptr);
}

xaml_result XAML_CALL set_completed(xaml_delegate<I, xaml_async_status>* h) noexcept override
{
m_handler = h;
if (m_status != xaml_async_started)
{
return invoke_completed();
}
return XAML_S_OK;
}

xaml_result invoke_completed() noexcept
{
if (m_handler)
{
return m_handler->invoke(this, m_status);
}
return XAML_S_OK;
}

xaml_ptr<I> get_return_object() noexcept { return this; }
std::suspend_always initial_suspend() const noexcept { return {}; }
auto final_suspend() noexcept
{
struct awaitable
{
xaml_async_promise_base* m_promise;

bool await_ready() const noexcept { return false; }
void await_resume() const noexcept {}

bool await_suspend(std::coroutine_handle<>) const noexcept
{
m_promise->invoke_completed();
return m_promise->release() > 0;
}
};
if (m_status == xaml_async_started) m_status = xaml_async_completed;
return awaitable{ this };
}

void unhandled_exception() noexcept
{
m_exception = std::current_exception();
m_status = xaml_async_error;
}

void rethrow_if_failed() const
{
if (m_status == xaml_async_error)
{
std::rethrow_exception(m_exception);
}
}

xaml_result XAML_CALL get_error() noexcept override
try
{
auto handle = get_handle();
while (!handle.done()) handle.resume();
rethrow_if_failed();
return XAML_S_OK;
}
XAML_CATCH_RETURN()

xaml_result XAML_CALL get_status(xaml_async_status* ptr) noexcept override
{
*ptr = m_status;
return XAML_S_OK;
}
};

auto operator co_await(xaml_ptr<xaml_async_action> action)
{
struct awaitable
{
xaml_ptr<xaml_async_action> m_action;

bool await_ready() const
{
xaml_async_status status;
XAML_THROW_IF_FAILED(m_action->get_status(&status));
return status != xaml_async_started;
}

void await_resume() const noexcept {}

void await_suspend(std::coroutine_handle<> h) const
{
auto action = m_action;
xaml_ptr<xaml_delegate<xaml_async_action, xaml_async_status>> handler;
XAML_THROW_IF_FAILED(xaml_delegate_new(
[h](xaml_ptr<xaml_async_action> const&, xaml_async_status) noexcept -> xaml_result {
try
{
h.resume();
return XAML_S_OK;
}
XAML_CATCH_RETURN()
},
&handler));
XAML_THROW_IF_FAILED(action->set_completed(handler));
XAML_THROW_IF_FAILED(action->get_error());
}
};
return awaitable{ action };
}

namespace std
{
template <typename... Args>
struct coroutine_traits<xaml_ptr<xaml_async_action>, Args...>
{
struct promise_type final : xaml_async_promise_base<promise_type, xaml_async_action>
{
void return_void() const noexcept {}
};
};
} // namespace std
#endif // __cplusplus

#endif // !XAML_ASYNC_ACTION_H
27 changes: 27 additions & 0 deletions async/include/xaml/async/info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef XAML_ASYNC_INFO_H
#define XAML_ASYNC_INFO_H

#include <xaml/object.h>

typedef enum xaml_async_status
{
xaml_async_started,
xaml_async_completed,
xaml_async_error
} xaml_async_status;

XAML_TYPE(xaml_async_status, { 0x2e1ff26a, 0x5de9, 0x4d44, { 0x8d, 0xbd, 0xcf, 0xf6, 0xd2, 0xe8, 0x12, 0xf7 } })

XAML_CLASS(xaml_async_info, { 0x0d9e61f6, 0x5eb4, 0x4d82, { 0x9e, 0xb0, 0x98, 0x2f, 0xf8, 0x20, 0x82, 0x23 } })

#define XAML_ASYNC_INFO_VTBL(type) \
XAML_VTBL_INHERIT(XAML_OBJECT_VTBL(type)); \
XAML_METHOD(get_error, type); \
XAML_METHOD(get_status, type, xaml_async_status*)

XAML_DECL_INTERFACE_(xaml_async_info, xaml_object)
{
XAML_DECL_VTBL(xaml_async_info, XAML_ASYNC_INFO_VTBL);
};

#endif // !XAML_ASYNC_INFO_H
8 changes: 8 additions & 0 deletions async/src/action.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <xaml/async/action.h>

using namespace std;

xaml_result XAML_CALL xaml_async_action_wait_all(xaml_vector_view<xaml_async_action>* actions) noexcept
{
return XAML_E_NOTIMPL;
}
6 changes: 6 additions & 0 deletions async/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
project(AsyncTest CXX)

file(GLOB TEST_SOURCE "src/*.cpp")

add_executable(async_test ${TEST_SOURCE})
target_link_libraries(async_test xaml_async stream_format nowide)
72 changes: 72 additions & 0 deletions async/test/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <chrono>
#include <nowide/iostream.hpp>
#include <sf/format.hpp>
#include <thread>
#include <xaml/async/action.h>

auto operator co_await(std::chrono::system_clock::duration duration)
{
struct awaitable
{
std::chrono::system_clock::duration m_duration;
std::thread m_thread;

explicit awaitable(std::chrono::system_clock::duration d)
: m_duration(d),
m_thread(
[d] {
if (d.count() > 0) std::this_thread::sleep_for(d);
})
{
}

bool await_ready() const
{
return m_duration.count() <= 0;
}

auto await_suspend(std::coroutine_handle<> h)
{
m_thread.join();
return h;
}

void await_resume() {}
};
return awaitable{ duration };
}

using namespace sf;
using nowide::cout;
using namespace std::chrono_literals;

xaml_ptr<xaml_async_action> foo()
{
println(cout, "Here is in foo.");
co_await 1s;
println(cout, "Here is also in foo.");
}

xaml_ptr<xaml_async_action> bar()
{
println(cout, "Here is in bar.");
auto task = foo();
println(cout, "Here is also in bar.");
co_await task;
println(cout, "Now back to bar once again.");
throw std::bad_alloc{};
}

int main()
{
auto action = bar();
try
{
XAML_THROW_IF_FAILED(action->get_error());
}
catch (xaml_result_error const& e)
{
println(cout, xaml_result_get_message(e.get_result()));
}
println(cout, "Back to main.");
}
4 changes: 3 additions & 1 deletion global/include/xaml/observable_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ xaml_result XAML_CALL xaml_vector_changed_args_new(xaml_vector_changed_action ac

XAML_TYPE_BASE(xaml_observable_vector_1, { 0xc84cb35f, 0x0a1c, 0x40e2, { 0x8e, 0x1c, 0x2c, 0x43, 0x0b, 0x1b, 0xb6, 0xcf } })

#define __XAML_DELEGATE_2_NAME(a, b) XAML_DELEGATE_2_NAME(a, b)
#ifndef __XAML_DELEGATE_2_NAME
#define __XAML_DELEGATE_2_NAME(a, b) XAML_DELEGATE_2_NAME(a, b)
#endif // !__XAML_DELEGATE_2_NAME

#define XAML_OBSERVABLE_VECTOR_1_VTBL(type, TN, TI) \
XAML_VTBL_INHERIT(XAML_VECTOR_1_VTBL(type, TN, TI)); \
Expand Down
8 changes: 4 additions & 4 deletions global/include/xaml/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@
#define XAML_META_API __XAML_IMPORT
#endif // !XAML_META_API

#ifndef XAML_ASYNC_API
#define XAML_ASYNC_API __XAML_IMPORT
#endif // !XAML_ASYNC_API

#ifndef XAML_UI_API
#define XAML_UI_API __XAML_IMPORT
#endif // !XAML_UI_API

#ifndef XAML_UI_META_API
#define XAML_UI_META_API __XAML_META_IMPORT
#endif // !XAML_UI_META_API

#ifndef XAML_UI_CONTROLS_API
#define XAML_UI_CONTROLS_API __XAML_IMPORT
#endif // !XAML_UI_CONTROLS_API
Expand Down