Skip to content

Commit

Permalink
Support error isolation/capture.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Sep 21, 2020
1 parent b166963 commit aeb893c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/alia/flow/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ on_init(context ctx, action<> on_init)
on_refresh(ctx, [&](auto) {
if (!data.initialized && on_init.is_ready())
{
perform_action(on_init);
isolate_errors(ctx, [&] { perform_action(on_init); });
mark_dirty_component(ctx);
data.initialized = true;
}
});
Expand All @@ -116,7 +117,8 @@ on_activate(context ctx, action<> on_activate)
on_refresh(ctx, [&](auto) {
if (!data.initialized && on_activate.is_ready())
{
perform_action(on_activate);
isolate_errors(ctx, [&] { perform_action(on_activate); });
mark_dirty_component(ctx);
data.initialized = true;
}
});
Expand Down
9 changes: 5 additions & 4 deletions src/alia/flow/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <alia/flow/components.hpp>
#include <alia/flow/data_graph.hpp>
#include <alia/flow/macros.hpp>
#include <alia/flow/try_catch.hpp>
#include <alia/system/interface.hpp>

// This file implements utilities for routing events through an alia content
Expand Down Expand Up @@ -262,7 +263,7 @@ on_value_change(context ctx, Signal signal, action<> on_change)
[&](auto const& new_value) {
if (!data->has_value || data->value != new_value)
{
perform_action(on_change);
isolate_errors(ctx, [&] { perform_action(on_change); });
mark_dirty_component(ctx);
data->has_value = true;
data->value = new_value;
Expand All @@ -271,7 +272,7 @@ on_value_change(context ctx, Signal signal, action<> on_change)
[&] {
if (data->has_value)
{
perform_action(on_change);
isolate_errors(ctx, [&] { perform_action(on_change); });
mark_dirty_component(ctx);
data->has_value = false;
}
Expand All @@ -290,7 +291,7 @@ on_value_gain(context ctx, Signal signal, action<> on_gain)
bool current_state = signal_has_value(signal);
if (current_state && !*saved_state)
{
perform_action(on_gain);
isolate_errors(ctx, [&] { perform_action(on_gain); });
mark_dirty_component(ctx);
}
*saved_state = current_state;
Expand All @@ -309,7 +310,7 @@ on_value_loss(context ctx, Signal signal, action<> on_loss)
bool current_state = signal_has_value(signal);
if (!current_state && *saved_state)
{
perform_action(on_loss);
isolate_errors(ctx, [&] { perform_action(on_loss); });
mark_dirty_component(ctx);
}
*saved_state = current_state;
Expand Down
22 changes: 22 additions & 0 deletions src/alia/flow/try_catch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ struct catch_block
#define alia_catch(pattern) ALIA_CATCH(pattern)
#endif

template<class Function>
void
isolate_errors(system& sys, Function&& function)
{
try
{
std::forward<Function>(function)();
}
catch (...)
{
if (sys.error_handler)
sys.error_handler(std::current_exception());
}
}

template<class Function>
void
isolate_errors(dataless_context ctx, Function&& function)
{
isolate_errors(get<system_tag>(ctx), std::forward<Function>(function));
}

} // namespace alia

#endif
6 changes: 6 additions & 0 deletions src/alia/system/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ refresh_system(system& sys)
};
}

void
set_error_handler(system& sys, std::function<void(std::exception_ptr)> handler)
{
sys.error_handler = handler;
}

} // namespace alia
6 changes: 6 additions & 0 deletions src/alia/system/interface.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef ALIA_SYSTEM_INTERFACE_HPP
#define ALIA_SYSTEM_INTERFACE_HPP

#include <functional>

namespace alia {

struct system;
Expand All @@ -11,6 +13,10 @@ system_needs_refresh(system const& sys);
void
refresh_system(system& sys);

void
set_error_handler(
system& sys, std::function<void(std::exception_ptr)> handler);

} // namespace alia

#endif
1 change: 1 addition & 0 deletions src/alia/system/internals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct system : noncopyable
std::unique_ptr<external_interface> external;
timer_event_scheduler scheduler;
component_container_ptr root_component;
std::function<void(std::exception_ptr)> error_handler;
};

void
Expand Down
33 changes: 33 additions & 0 deletions unit_tests/flow/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,36 @@ TEST_CASE("on_value events", "[flow][events]")
REQUIRE(change_count == 4);
REQUIRE(change_shadow == 4);
}

TEST_CASE("error isolation", "[flow][events]")
{
int n = 0;

alia::system sys;
initialize_system(sys, [&](context ctx) {
on_value_change(ctx, value(n), lambda_action([&] {
static_cast<void>(std::string("abc").at(n));
}));
});

int error_count = 0;
set_error_handler(sys, [&](std::exception_ptr) { ++error_count; });

refresh_system(sys);
REQUIRE(error_count == 0);

n = 2;
refresh_system(sys);
REQUIRE(error_count == 0);

++n;
refresh_system(sys);
REQUIRE(error_count == 1);

refresh_system(sys);
REQUIRE(error_count == 1);

++n;
refresh_system(sys);
REQUIRE(error_count == 2);
}

0 comments on commit aeb893c

Please sign in to comment.