Skip to content

Commit 906c686

Browse files
committed
Revert "Simplify experimental validation"
This reverts commit 73046b5.
1 parent 73046b5 commit 906c686

File tree

4 files changed

+176
-34
lines changed

4 files changed

+176
-34
lines changed

src/alia/signals/core.hpp

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,27 @@ struct untyped_signal_base
162162
// Clear the signal.
163163
virtual void
164164
clear() const = 0;
165+
166+
// WARNING: EXPERIMENTAL VALIDATION STUFF FOLLOWS...
167+
168+
// Handle a validation error.
169+
//
170+
// This is called when there's an attempt to write to the signal and a
171+
// validation_error is thrown. (The argument is the error.)
172+
//
173+
// The return value should be true iff the validation error was handled.
174+
//
175+
virtual bool invalidate(std::exception_ptr) const
176+
{
177+
return false;
178+
}
179+
180+
// Is this signal currently invalidated?
181+
virtual bool
182+
is_invalidated() const
183+
{
184+
return false;
185+
}
165186
};
166187

167188
template<class Value>
@@ -371,6 +392,16 @@ struct signal_ref
371392
{
372393
ref_->write(std::move(value));
373394
}
395+
bool
396+
invalidate(std::exception_ptr error) const override
397+
{
398+
return ref_->invalidate(error);
399+
}
400+
bool
401+
is_invalidated() const override
402+
{
403+
return ref_->is_invalidated();
404+
}
374405

375406
private:
376407
signal_interface<Value> const* ref_;
@@ -441,37 +472,6 @@ read_signal(Signal const& signal)
441472
return signal.read();
442473
}
443474

444-
// signal_is_clearable<Signal>::value yields a compile-time boolean indicating
445-
// whether or not the given signal type supports clearing.
446-
template<class Signal>
447-
struct signal_is_clearable : signal_capability_level_is_compatible<
448-
signal_clearable,
449-
Signal::capabilities::writing>
450-
{
451-
};
452-
453-
// is_clearable_signal_type<T>::value yields a compile-time boolean indicating
454-
// whether or not T is an alia signal that supports clearing.
455-
template<class T>
456-
struct is_clearable_signal_type : std::conditional_t<
457-
is_signal_type<T>::value,
458-
signal_is_clearable<T>,
459-
std::false_type>
460-
{
461-
};
462-
463-
// Clear a signal's value.
464-
// Unlike calling signal.clear() directly, this will generate a compile-time
465-
// error if the signal's type doesn't support clearing.
466-
// Note that if the signal isn't ready to write, this is a no op.
467-
template<class Signal>
468-
std::enable_if_t<signal_is_clearable<Signal>::value>
469-
clear_signal(Signal const& signal)
470-
{
471-
if (signal.ready_to_write())
472-
signal.clear();
473-
}
474-
475475
// When a value is written to a signal, the signal is allowed to throw a
476476
// validation_error if the value isn't acceptable.
477477
struct validation_error : exception
@@ -529,9 +529,12 @@ write_signal(Signal const& signal, Value value)
529529
}
530530
catch (validation_error&)
531531
{
532-
// EXPERIMENTAL VALIDATION LOGIC
533-
if constexpr (signal_is_clearable<Signal>::value)
534-
clear_signal(signal);
532+
// EXPERIMENTAL VALIDATION LOGIC: Try to let the signal handle the
533+
// validation error (at some level). If it can't, rethrow the
534+
// exception.
535+
auto e = std::current_exception();
536+
if (!signal.invalidate(e))
537+
std::rethrow_exception(e);
535538
}
536539
}
537540
}
@@ -627,6 +630,37 @@ forward_signal(Signal const& signal)
627630
return signal.read();
628631
}
629632

633+
// signal_is_clearable<Signal>::value yields a compile-time boolean indicating
634+
// whether or not the given signal type supports clearing.
635+
template<class Signal>
636+
struct signal_is_clearable : signal_capability_level_is_compatible<
637+
signal_clearable,
638+
Signal::capabilities::writing>
639+
{
640+
};
641+
642+
// is_clearable_signal_type<T>::value yields a compile-time boolean indicating
643+
// whether or not T is an alia signal that supports clearing.
644+
template<class T>
645+
struct is_clearable_signal_type : std::conditional_t<
646+
is_signal_type<T>::value,
647+
signal_is_clearable<T>,
648+
std::false_type>
649+
{
650+
};
651+
652+
// Clear a signal's value.
653+
// Unlike calling signal.clear() directly, this will generate a compile-time
654+
// error if the signal's type doesn't support clearing.
655+
// Note that if the signal isn't ready to write, this is a no op.
656+
template<class Signal>
657+
std::enable_if_t<signal_is_clearable<Signal>::value>
658+
clear_signal(Signal const& signal)
659+
{
660+
if (signal.ready_to_write())
661+
signal.clear();
662+
}
663+
630664
} // namespace alia
631665

632666
#endif

src/alia/signals/operators.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,22 @@ struct signal_mux : signal<
399399
else
400400
f_.clear();
401401
}
402+
bool
403+
invalidate(std::exception_ptr error) const override
404+
{
405+
if (condition_.read())
406+
return t_.invalidate(error);
407+
else
408+
return f_.invalidate(error);
409+
}
410+
bool
411+
is_invalidated() const override
412+
{
413+
if (condition_.read())
414+
return t_.is_invalidated();
415+
else
416+
return f_.is_invalidated();
417+
}
402418

403419
private:
404420
Condition condition_;

src/alia/signals/utilities.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,16 @@ struct signal_wrapper : signal<Derived, Value, Capabilities>
191191
{
192192
wrapped_.clear();
193193
}
194+
bool
195+
invalidate(std::exception_ptr error) const override
196+
{
197+
return wrapped_.invalidate(error);
198+
}
199+
bool
200+
is_invalidated() const override
201+
{
202+
return wrapped_.is_invalidated();
203+
}
194204

195205
protected:
196206
Wrapped wrapped_;
@@ -231,6 +241,16 @@ struct casting_signal_wrapper : signal<Derived, Value, Capabilities>
231241
{
232242
wrapped_.clear();
233243
}
244+
bool
245+
invalidate(std::exception_ptr error) const override
246+
{
247+
return wrapped_.invalidate(error);
248+
}
249+
bool
250+
is_invalidated() const override
251+
{
252+
return wrapped_.is_invalidated();
253+
}
234254

235255
protected:
236256
Wrapped wrapped_;

src/alia/signals/validation.hpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#ifndef ALIA_SIGNALS_VALIDATION_HPP
2+
#define ALIA_SIGNALS_VALIDATION_HPP
3+
4+
#include <alia/signals/core.hpp>
5+
6+
namespace alia {
7+
8+
struct signal_validation_data
9+
{
10+
captured_id value_id;
11+
std::exception_ptr error;
12+
};
13+
14+
template<class Wrapped>
15+
struct validated_signal : signal_wrapper<validated_signal<Wrapped>, Wrapped>
16+
{
17+
validated_signal()
18+
{
19+
}
20+
validated_signal(signal_validation_data* data, Wrapped wrapped)
21+
: validated_signal::signal_wrapper(wrapped), data_(data)
22+
{
23+
}
24+
bool
25+
has_value() const override
26+
{
27+
return !data_->error && this->wrapped_.has_value();
28+
}
29+
bool
30+
invalidate(std::exception_ptr error) const override
31+
{
32+
data_->error = error;
33+
this->wrapped_.invalidate(error);
34+
return true;
35+
}
36+
bool
37+
is_invalidated() const override
38+
{
39+
return data_->error || this->wrapped_.is_invalidated();
40+
}
41+
42+
private:
43+
signal_validation_data* data_;
44+
};
45+
46+
template<class Signal>
47+
auto
48+
enforce_validity(
49+
dataless_context ctx, Signal signal, signal_validation_data& data)
50+
{
51+
refresh_handler(ctx, [&](auto) {
52+
if (!signal.is_invalidated()
53+
&& !data.value_id.matches(signal.value_id()))
54+
{
55+
data.error = nullptr;
56+
data.value_id.capture(signal.value_id());
57+
}
58+
});
59+
return validated_signal<Signal>(&data, signal);
60+
}
61+
62+
template<class Signal>
63+
auto
64+
enforce_validity(context ctx, Signal signal)
65+
{
66+
auto& data = get_cached_data<signal_validation_data>(ctx);
67+
return enforce_validity(ctx, signal, data);
68+
}
69+
70+
} // namespace alia
71+
72+
#endif

0 commit comments

Comments
 (0)