62#define REGISTER_FUTURE_STATUS_LISTENERS(ABSTRACT_TYPE, HANDLER1, ...) \
65 void future_on_status_change_dispatch(const AbstractFuture& future, FutureStatus status) \
67 dispatch_handler<ABSTRACT_TYPE, AbstractFuture>::future_on_status_change< \
68 HANDLER1, ##__VA_ARGS__>(future, status); \
70 void future_on_status_change_dispatch(const AbstractFakeFuture& future, FutureStatus status)\
72 dispatch_handler<ABSTRACT_TYPE, AbstractFakeFuture>::future_on_status_change< \
73 HANDLER1, ##__VA_ARGS__>(future, status); \
90#define REGISTER_FUTURE_STATUS_NO_LISTENERS() \
91 void future::future_on_status_change_dispatch(const AbstractFuture&, FutureStatus) {} \
92 void future::future_on_status_change_dispatch(const AbstractFakeFuture&, FutureStatus) {}
123#define REGISTER_FUTURE_OUTPUT_LISTENERS(ABSTRACT_TYPE, HANDLER1, ...) \
126 void future_on_output_change_dispatch(const AbstractFuture& future) \
128 dispatch_handler<ABSTRACT_TYPE, AbstractFuture>::future_on_output_change< \
129 HANDLER1, ##__VA_ARGS__>(future); \
131 void future_on_output_change_dispatch(const AbstractFakeFuture& future) \
133 dispatch_handler<ABSTRACT_TYPE, AbstractFakeFuture>::future_on_output_change< \
134 HANDLER1, ##__VA_ARGS__>(future); \
150#define REGISTER_FUTURE_OUTPUT_NO_LISTENERS() \
151 void future::future_on_output_change_dispatch(const AbstractFuture&) {} \
152 void future::future_on_output_change_dispatch(const AbstractFakeFuture&) {}
166#define REGISTER_FUTURE_NO_LISTENERS() \
167 REGISTER_FUTURE_STATUS_NO_LISTENERS() \
168 REGISTER_FUTURE_OUTPUT_NO_LISTENERS()
178#define DECL_FUTURE_LISTENERS_FRIEND \
179 template<typename> friend struct future::dispatch_handler_impl;
363 template<
typename OSTREAM> OSTREAM& operator<<(OSTREAM& out,
FutureStatus status)
371 return F(
"NOT_READY");
386 return out << convert(status);
391 class AbstractFuture;
392 extern void future_on_status_change_dispatch(
const AbstractFuture&,
FutureStatus);
393 extern void future_on_output_change_dispatch(
const AbstractFuture&);
394 class AbstractFakeFuture;
395 extern void future_on_status_change_dispatch(
const AbstractFakeFuture&,
FutureStatus);
396 extern void future_on_output_change_dispatch(
const AbstractFakeFuture&);
529 if (input_size_ == 0)
531 chunk = *input_current_++;
565 if (size > input_size_)
567 memcpy(chunk, input_current_, size);
568 input_current_ += size;
621 if (output_size_ == 0)
659 *output_current_++ = chunk;
663 if (output_size_ == 0)
701 if (size > output_size_)
775 AbstractFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
777 : output_data_{output_data}, output_current_{output_data}, output_size_{output_size},
778 input_data_{input_data}, input_current_{input_data}, input_size_{input_size},
779 notifications_{notifications} {}
782 AbstractFuture(
const AbstractFuture&) =
delete;
783 AbstractFuture& operator=(
const AbstractFuture&) =
delete;
784 AbstractFuture(AbstractFuture&&) =
delete;
785 AbstractFuture& operator=(AbstractFuture&&) =
delete;
787 ~AbstractFuture() =
default;
790 void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
794 output_data_ = output_current_ = output_data;
795 output_size_ = output_size;
796 input_data_ = input_current_ = input_data;
797 input_size_ = input_size;
802 bool can_replace_input_()
const
804 return (input_current_ == input_data_);
809 void callback_status()
812 future_on_status_change_dispatch(*
this, status_);
815 void callback_output()
818 future_on_output_change_dispatch(*
this);
824 uint8_t* output_data_ =
nullptr;
825 uint8_t* output_current_ =
nullptr;
826 uint8_t output_size_ = 0;
828 uint8_t* input_data_ =
nullptr;
829 uint8_t* input_current_ =
nullptr;
830 uint8_t input_size_ = 0;
834 template<
typename F>
friend class AbstractFuturesGroup;
865 template<
typename OUT_ =
void,
typename IN_ =
void>
868 static_assert(
sizeof(OUT_) <= UINT8_MAX,
"OUT type must be strictly smaller than 256 bytes");
869 static_assert(
sizeof(IN_) <= UINT8_MAX,
"IN type must be strictly smaller than 256 bytes");
900 notifications}, input_{input} {}
916 AbstractFuture::reset_(output_buffer_,
sizeof(
OUT), input_buffer_,
sizeof(
IN));
936 if (!can_replace_input_())
return false;
994 uint8_t output_buffer_[
sizeof(
OUT)];
999 uint8_t input_buffer_[
sizeof(
IN)];
1006 template<
typename OUT_>
1007 class Future<OUT_, void> :
public AbstractFuture
1009 static_assert(
sizeof(OUT_) <= UINT8_MAX,
"OUT type must be strictly smaller than 256 bytes");
1016 static constexpr uint8_t
IN_SIZE = 0;
1019 : AbstractFuture{output_buffer_, sizeof(
OUT), nullptr, 0, notifications} {}
1020 ~Future() =
default;
1025 AbstractFuture::reset_(output_buffer_,
sizeof(
OUT),
nullptr, 0);
1041 uint8_t output_buffer_[
sizeof(
OUT)];
1047 template<
typename IN_>
1048 class Future<void, IN_> :
public AbstractFuture
1050 static_assert(
sizeof(IN_) <= UINT8_MAX,
"IN type must be strictly smaller than 256 bytes");
1056 static constexpr uint8_t
OUT_SIZE = 0;
1057 static constexpr uint8_t
IN_SIZE =
sizeof(
IN);
1060 : AbstractFuture{
nullptr, 0, input_buffer_,
sizeof(
IN), notifications}, input_{input} {}
1061 ~Future() =
default;
1066 AbstractFuture::reset_(
nullptr, 0, input_buffer_,
sizeof(
IN));
1072 if (!can_replace_input_())
return false;
1097 uint8_t input_buffer_[
sizeof(
IN)];
1104 class Future<void, void> :
public AbstractFuture
1110 static constexpr uint8_t
OUT_SIZE = 0;
1111 static constexpr uint8_t
IN_SIZE = 0;
1114 : AbstractFuture{nullptr, 0,nullptr, 0, notifications} {}
1115 ~Future() =
default;
1120 AbstractFuture::reset_(
nullptr, 0,
nullptr, 0);
1163 uint8_t get_storage_value_size_()
const
1168 bool get_storage_value_(uint8_t& chunk)
1171 chunk = *input_current_++;
1176 bool get_storage_value_(uint8_t* chunk, uint8_t size)
1178 memcpy(chunk, input_current_, size);
1179 input_current_ += size;
1180 input_size_ -= size;
1187 uint8_t get_future_value_size_()
const
1189 return output_size_;
1192 bool set_future_finish_()
1198 bool set_future_value_(uint8_t chunk)
1201 *output_current_++ = chunk;
1207 bool set_future_value_(
const uint8_t* chunk, uint8_t size)
1211 set_future_value_(*chunk++);
1216 template<
typename T>
bool set_future_value_(
const T& value)
1218 return set_future_value_(
reinterpret_cast<const uint8_t*
>(&value),
sizeof(T));
1221 bool set_future_error_(
int error)
1233 AbstractFakeFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
1235 : output_current_{output_data}, output_size_{output_size},
1236 input_current_{input_data}, input_size_{input_size},
1237 notifications_{notifications} {}
1248 void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
1251 output_current_ = output_data;
1252 output_size_ = output_size;
1253 input_current_ = input_data;
1254 input_size_ = input_size;
1259 bool can_replace_input_()
const
1266 void callback_status()
1269 future_on_status_change_dispatch(*
this, status());
1272 void callback_output()
1275 future_on_output_change_dispatch(*
this);
1280 uint8_t* output_current_ =
nullptr;
1281 uint8_t output_size_ = 0;
1283 uint8_t* input_current_ =
nullptr;
1284 uint8_t input_size_ = 0;
1298 template<
typename OUT_ =
void,
typename IN_ =
void>
1301 static_assert(
sizeof(OUT_) <= UINT8_MAX,
"OUT type must be strictly smaller than 256 bytes");
1302 static_assert(
sizeof(IN_) <= UINT8_MAX,
"IN type must be strictly smaller than 256 bytes");
1309 static constexpr uint8_t OUT_SIZE =
sizeof(OUT);
1310 static constexpr uint8_t IN_SIZE =
sizeof(IN);
1315 notifications}, input_{input} {}
1320 void reset_(
const IN& input = IN{})
1322 AbstractFakeFuture::reset_(output_buffer_,
sizeof(OUT), input_buffer_,
sizeof(IN));
1326 bool reset_input_(
const IN& input)
1332 bool get(OUT& result)
1339 const IN& get_input()
const
1353 uint8_t output_buffer_[
sizeof(OUT)];
1358 uint8_t input_buffer_[
sizeof(IN)];
1363 template<
typename OUT_>
1366 static_assert(
sizeof(OUT_) <= UINT8_MAX,
"OUT type must be strictly smaller than 256 bytes");
1372 static constexpr uint8_t OUT_SIZE =
sizeof(OUT);
1373 static constexpr uint8_t IN_SIZE = 0;
1379 ~FakeFuture() =
default;
1384 AbstractFakeFuture::reset_(output_buffer_,
sizeof(OUT),
nullptr, 0);
1387 bool get(OUT& result)
1397 uint8_t output_buffer_[
sizeof(OUT)];
1403 template<
typename IN_>
1404 class FakeFuture<void, IN_> :
public AbstractFakeFuture
1406 static_assert(
sizeof(IN_) <= UINT8_MAX,
"IN type must be strictly smaller than 256 bytes");
1412 static constexpr uint8_t OUT_SIZE = 0;
1413 static constexpr uint8_t IN_SIZE =
sizeof(IN);
1416 : AbstractFakeFuture{
nullptr, 0, input_buffer_,
sizeof(IN), notifications}, input_{input} {}
1418 ~FakeFuture() =
default;
1421 void reset_(
const IN& input = IN{})
1423 AbstractFakeFuture::reset_(
nullptr, 0, input_buffer_,
sizeof(IN));
1427 bool reset_input_(
const IN& input)
1439 const IN& get_input()
const
1452 uint8_t input_buffer_[
sizeof(IN)];
1459 class FakeFuture<void, void> :
public AbstractFakeFuture
1465 static constexpr uint8_t OUT_SIZE = 0;
1466 static constexpr uint8_t IN_SIZE = 0;
1469 : AbstractFakeFuture{nullptr, 0, nullptr, 0, notifications} {}
1471 ~FakeFuture() =
default;
1475 AbstractFakeFuture::reset_(
nullptr, 0,
nullptr, 0);
1487 template<
typename F>
struct Future_trait
1489 static constexpr const bool IS_FUTURE =
false;
1490 static constexpr const bool IS_ABSTRACT =
false;
1491 static constexpr const bool IS_FAKE =
false;
1493 template<>
struct Future_trait<AbstractFuture>
1495 static constexpr const bool IS_FUTURE =
true;
1496 static constexpr const bool IS_ABSTRACT =
true;
1497 static constexpr const bool IS_FAKE =
false;
1499 template<
typename OUT,
typename IN>
struct Future_trait<Future<OUT, IN>>
1501 static constexpr const bool IS_FUTURE =
true;
1502 static constexpr const bool IS_ABSTRACT =
false;
1503 static constexpr const bool IS_FAKE =
false;
1505 template<>
struct Future_trait<AbstractFakeFuture>
1507 static constexpr const bool IS_FUTURE =
true;
1508 static constexpr const bool IS_ABSTRACT =
true;
1509 static constexpr const bool IS_FAKE =
true;
1511 template<
typename OUT,
typename IN>
struct Future_trait<FakeFuture<OUT, IN>>
1513 static constexpr const bool IS_FUTURE =
true;
1514 static constexpr const bool IS_ABSTRACT =
false;
1515 static constexpr const bool IS_FAKE =
true;
1577 static_assert(Future_trait<F>::IS_FUTURE,
"F must be a Future");
1578 static_assert(Future_trait<F>::IS_ABSTRACT,
"F must be an abstract Future");
1604 :
F{nullptr, 0, nullptr, 0, notifications} {}
1622 num_ready_ = (actual_size != 0 ? actual_size : futures.size());
1640 this->set_future_error_(
future.error());
1648 if (--num_ready_ == 0)
1649 this->set_future_finish_();
1658 uint16_t num_ready_ = 0;
1662 template<
typename F>
1663 struct dispatch_handler_impl
1665 template<
bool DUMMY>
static void future_on_status_change_helper(
const F&, FutureStatus)
1670 template<
bool DUMMY,
typename HANDLER1_,
typename... HANDLERS_>
1671 static void future_on_status_change_helper(
const F&
future, FutureStatus status)
1673 HANDLER1_* handler = interrupt::HandlerHolder<HANDLER1_>::handler();
1674 if (handler !=
nullptr)
1675 handler->on_status_change(
future, status);
1677 future_on_status_change_helper<
true, HANDLERS_...>(
future, status);
1680 template<
typename... HANDLERS_>
1681 static void future_on_status_change(
const F&
future, FutureStatus status)
1684 future_on_status_change_helper<
true, HANDLERS_...>(
future, status);
1687 template<
bool DUMMY>
static void future_on_output_change_helper(
const F&)
1692 template<
bool DUMMY,
typename HANDLER1_,
typename... HANDLERS_>
1693 static void future_on_output_change_helper(
const F&
future)
1695 HANDLER1_* handler = interrupt::HandlerHolder<HANDLER1_>::handler();
1696 if (handler !=
nullptr)
1697 handler->on_output_change(
future);
1699 future_on_output_change_helper<
true, HANDLERS_...>(
future);
1702 template<
typename... HANDLERS_>
1703 static void future_on_output_change(
const F&
future)
1706 future_on_output_change_helper<
true, HANDLERS_...>(
future);
1710 template<
typename F1,
typename F2>
1711 struct dispatch_handler
1713 template<
typename... HANDLERS_>
1714 static void future_on_status_change(
const F2&, FutureStatus)
1718 template<
typename... HANDLERS_>
1719 static void future_on_output_change(
const F2&)
1726 struct dispatch_handler<AbstractFuture, AbstractFuture>
1728 template<
typename... HANDLERS_>
1729 static void future_on_status_change(
const AbstractFuture&
future, FutureStatus status)
1731 dispatch_handler_impl<AbstractFuture>::future_on_status_change<HANDLERS_...>(
1734 template<
typename... HANDLERS_>
1735 static void future_on_output_change(
const AbstractFuture&
future)
1737 dispatch_handler_impl<AbstractFuture>::future_on_output_change<HANDLERS_...>(
future);
1742 struct dispatch_handler<AbstractFakeFuture, AbstractFakeFuture>
1744 template<
typename... HANDLERS_>
1745 static void future_on_status_change(
const AbstractFakeFuture&
future, FutureStatus status)
1747 dispatch_handler_impl<AbstractFakeFuture>::future_on_status_change<HANDLERS_...>(
1750 template<
typename... HANDLERS_>
1751 static void future_on_output_change(
const AbstractFakeFuture&
future)
1753 dispatch_handler_impl<AbstractFakeFuture>::future_on_output_change<HANDLERS_...>(
future);
Base class for all FakeFutures.
Base class for all Futures.
bool set_future_value_(uint8_t chunk)
Add one byte to the output value content of this Future.
bool get_storage_value_(uint8_t *chunk, uint8_t size)
Get size bytes from the input storage value of this Future.
bool set_future_value_(const T &value)
Set the output value content of this Future.
uint8_t get_future_value_size_() const
Check the number of bytes remaining to write to the output value of this Future.
bool set_future_error_(int error)
Mark this Future as FutureStatus::ERROR.
bool set_future_finish_()
Mark this Future as FutureStatus::READY.
bool get_storage_value_(uint8_t &chunk)
Get one byte from the input storage value of this Future.
FutureStatus status() const
The current status of this Future.
FutureStatus await() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error.
int error() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error,...
uint8_t get_storage_value_size_() const
Check the number of bytes remaining to read from this Future.
bool set_future_value_(const uint8_t *chunk, uint8_t size)
Add several bytes to the output value content of this Future.
Abstract class to allow aggregation of several futures.
static constexpr const uint16_t NO_LIMIT
Specific size value indicating this group has an unlimited (and unknown at construction time) number ...
void on_status_change_pre_step(const F &future, FutureStatus status)
This must be called by subclasses on_status_change() method, after checking that future is one of the...
AbstractFuturesGroup(FutureNotification notifications=FutureNotification::NONE)
Construct a new AbstractFuturesGroup.
void init(utils::range< F * > futures, uint16_t actual_size=0)
Called from constructors of subclasses, this method allows this group to listen for the status of all...
Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future.
Represent a value to be obtained, in some asynchronous way, in the future.
IN & get_input()
Return the input storage value as it was initially set (or reset through reset_input_()),...
IN_ IN
Type of the input value of this Future.
bool reset_input_(const IN &input)
Reset the input storage value held by this Future with a new value.
const IN & get_input() const
Return the input storage value as it was initially set (or reset through reset_input_()),...
OUT_ OUT
Type of the output value of this Future.
static constexpr uint8_t IN_SIZE
Size of the input value of this Future.
static constexpr uint8_t OUT_SIZE
Size of the output value of this Future.
bool get(OUT &result)
Wait until an output value has been completely filled in this Future and return that value to the cal...
void reset_(const IN &input=IN{})
This method completely resets this future (for reuse from scratch), as if it was just constructed.
Future(const IN &input=IN{}, FutureNotification notifications=FutureNotification::NONE)
Construct a new Future.
Iterable class that can embed arrays or initializer lists through implicit conversion.
Common errors definition.
#define F(ptr)
Force string constant to be stored as flash storage.
General API for handling AVR interrupt vectors.
Utilities to convert arrays into an iterable (usable if for x: list construct).
constexpr const int EINVAL
Invalid argument or invalid Future.
constexpr const int EMSGSIZE
Message too long.
Contains the API around Future implementation.
FutureStatus
Status of a Future.
@ READY
The status of a Future once its output value has been fully set by a provider.
@ NOT_READY
The status of a Future immediately after it has been constructed.
@ ERROR
The status of a Future once a value provider has reported an error to it.
@ INVALID
The status of a Future that has been moved, if it was NOT_READY before moving.
FutureNotification
Notification(s) dispatched by a Future.
@ OUTPUT
Notification is dispatched whenever the Future output buffer gets filled, even partly.
@ STATUS
Notification is dispatched whenever the Future status changes.
@ BOTH
Notification is dispatched whenever the Future status changes or the Future output buffer gets filled...
@ NONE
No notification is dispatched by the Future.
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...