FastArduino  v1.8
C++ library to build fast but small Arduino/AVR projects
future.h
Go to the documentation of this file.
1 // Copyright 2016-2021 Jean-Francois Poilpret
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
23 #ifndef FUTURE_HH
24 #define FUTURE_HH
25 
26 #include <string.h>
27 #include "iterator.h"
28 #include "errors.h"
29 #include "move.h"
30 #include "streams.h"
31 #include "time.h"
32 
109 namespace future
110 {
118  enum class FutureStatus : uint8_t
119  {
132  NOT_READY = 0,
133 
142  READY,
143 
151  ERROR,
152 
157  INVALID
158  };
159 
163 
175  template<typename F> class FutureStatusListener
176  {
177  protected:
183  virtual void on_status_change(const F& future, FutureStatus new_status) = 0;
184  friend F;
185  };
186 
199  template<typename F> class FutureOutputListener
200  {
201  protected:
212  virtual void on_output_change(const F& future, uint8_t* output_data, uint8_t* output_current) = 0;
213  friend F;
214  };
215 
223  {
224  public:
231  {
232  return status_;
233  }
234 
245  {
246  while (status_ == FutureStatus::NOT_READY)
247  time::yield();
248  return status_;
249  }
250 
262  int error() const
263  {
264  switch (await())
265  {
266  case FutureStatus::ERROR:
267  return error_;
268 
269  case FutureStatus::READY:
270  return 0;
271 
272  default:
273  // This should never happen
274  return errors::EINVAL;
275  }
276  }
277 
278  // Methods called by a Future consumer
279  //=====================================
280 
294  uint8_t get_storage_value_size_() const
295  {
296  return input_size_;
297  }
298 
323  bool get_storage_value_(uint8_t& chunk)
324  {
325  // Check all bytes have not been transferred yet
326  if (input_size_ == 0)
327  return false;
328  chunk = *input_current_++;
329  --input_size_;
330  return true;
331  }
332 
359  bool get_storage_value_(uint8_t* chunk, uint8_t size)
360  {
361  // Check size does not go beyond transferrable size
362  if (size > input_size_)
363  return false;
364  memcpy(chunk, input_current_, size);
365  input_current_ += size;
366  input_size_ -= size;
367  return true;
368  }
369 
370  // Methods called by a Future supplier
371  //=====================================
372 
388  uint8_t get_future_value_size_() const
389  {
390  return output_size_;
391  }
392 
414  {
415  // Check this future is waiting for data
416  if (status_ != FutureStatus::NOT_READY)
417  return false;
418  if (output_size_ == 0)
419  {
420  status_ = FutureStatus::READY;
421  callback_status();
422  }
423  return true;
424  }
425 
450  bool set_future_value_(uint8_t chunk)
451  {
452  // Check this future is waiting for data
453  if (status_ != FutureStatus::NOT_READY)
454  return false;
455  // Update Future value chunk
456  *output_current_++ = chunk;
457  // Is that the last chunk?
458  --output_size_;
459  callback_output();
460  if (output_size_ == 0)
461  {
462  status_ = FutureStatus::READY;
463  callback_status();
464  }
465  return true;
466  }
467 
495  bool set_future_value_(const uint8_t* chunk, uint8_t size)
496  {
497  // Check size does not go beyond expected size
498  if (size > output_size_)
499  {
500  // Store error
502  return false;
503  }
504  while (size--)
505  {
506  if (!set_future_value_(*chunk++)) return false;
507  }
508  return true;
509  }
510 
536  template<typename T> bool set_future_value_(const T& value)
537  {
538  return set_future_value_(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
539  }
540 
559  {
560  // Check this future is waiting for data
561  if ((error == 0) || (status_ != FutureStatus::NOT_READY))
562  return false;
563  error_ = error;
564  status_ = FutureStatus::ERROR;
565  callback_status();
566  return true;
567  }
568 
574 
580 
581  protected:
583  // "default" constructor
584  AbstractFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
585  STATUS_LISTENER* status_listener = nullptr, OUTPUT_LISTENER* output_listener = nullptr)
586  : output_data_{output_data}, output_current_{output_data}, output_size_{output_size},
587  input_data_{input_data}, input_current_{input_data}, input_size_{input_size},
588  status_listener_{status_listener}, output_listener_{output_listener} {}
589 
590  // these constructors are forbidden (subclass ctors shall call above move/copy ctor instead)
591  AbstractFuture(const AbstractFuture&) = delete;
592  AbstractFuture& operator=(const AbstractFuture&) = delete;
593  AbstractFuture(AbstractFuture&&) = delete;
594  AbstractFuture& operator=(AbstractFuture&&) = delete;
595 
596  ~AbstractFuture() = default;
597 
598  // This method is called by subclasses to completely reset this future (for reuse from scratch)
599  void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
600  {
601  status_ = FutureStatus::NOT_READY;
602  error_ = 0;
603  output_data_ = output_current_ = output_data;
604  output_size_ = output_size;
605  input_data_ = input_current_ = input_data;
606  input_size_ = input_size;
607  }
608 
609  // This method is called by subclass to check if input is replaceable,
610  // i.e. it has not been read yet
611  bool can_replace_input_() const
612  {
613  return (input_current_ == input_data_);
614  }
615 
616  // This method is called by subclass in their move constructor and assignment operator
617  void move_(AbstractFuture&& that, uint8_t full_output_size, uint8_t full_input_size)
618  {
619  // Now copy all attributes from rhs (output_data_ was already initialized when this was constructed)
620  status_listener_ = that.status_listener_;
621  output_listener_ = that.output_listener_;
622 
623  const FutureStatus status = that.status_;
624  status_ = status;
625  // Make rhs Future invalid
626  if (status == FutureStatus::NOT_READY)
627  that.status_ = FutureStatus::INVALID;
628 
629  error_ = that.error_;
630  const uint8_t output_size = that.output_size_;
631  // Calculate data pointer attribute for next set value calls
632  output_current_ = output_data_ + full_output_size - output_size;
633  output_size_ = output_size;
634 
635  const uint8_t input_size = that.input_size_;
636  // Calculate data pointer attribute for next set value calls
637  input_current_ = input_data_ + full_input_size - input_size;
638  input_size_ = input_size;
639  }
641 
642  private:
643  void callback_status()
644  {
645  if (status_listener_ != nullptr)
646  status_listener_->on_status_change(*this, status_);
647  }
648 
649  void callback_output()
650  {
651  if (output_listener_ != nullptr)
652  output_listener_->on_output_change(*this, output_data_, output_current_);
653  }
654 
655  volatile FutureStatus status_ = FutureStatus::NOT_READY;
656  int error_ = 0;
657 
658  uint8_t* output_data_ = nullptr;
659  uint8_t* output_current_ = nullptr;
660  uint8_t output_size_ = 0;
661 
662  uint8_t* input_data_ = nullptr;
663  uint8_t* input_current_ = nullptr;
664  uint8_t input_size_ = 0;
665 
666  STATUS_LISTENER* status_listener_ = nullptr;
667  OUTPUT_LISTENER* output_listener_ = nullptr;
668 
669  template<typename F> friend class AbstractFuturesGroup;
670  };
671 
700  template<typename OUT_ = void, typename IN_ = void>
701  class Future : public AbstractFuture
702  {
703  static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
704  static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
705 
706  public:
708  using OUT = OUT_;
710  using IN = IN_;
711 
713  static constexpr uint8_t OUT_SIZE = sizeof(OUT);
715  static constexpr uint8_t IN_SIZE = sizeof(IN);
716 
734  explicit Future(const IN& input = IN{}, STATUS_LISTENER* status_listener = nullptr,
735  OUTPUT_LISTENER* output_listener = nullptr)
736  : AbstractFuture{output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN),
737  status_listener, output_listener}, input_{input} {}
738 
740  ~Future() = default;
741  Future(Future&& that) : AbstractFuture{output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN)}
742  {
743  move(std::move(that));
744  }
745  Future& operator=(Future&& that)
746  {
747  if (this == &that) return *this;
748  move(std::move(that));
749  return *this;
750  }
751 
752  Future(const Future&) = delete;
753  Future& operator=(const Future&) = delete;
755 
764  void reset_(const IN& input = IN{})
765  {
766  AbstractFuture::reset_(output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN));
767  input_ = input;
768  }
769 
784  bool reset_input_(const IN& input)
785  {
786  if (!can_replace_input_()) return false;
787  input_ = input;
788  return true;
789  }
790 
811  bool get(OUT& result)
812  {
813  if (await() != FutureStatus::READY)
814  return false;
815  result = output_;
816  return true;
817  }
818 
819  protected:
825  const IN& get_input() const
826  {
827  return input_;
828  }
829 
836  {
837  return input_;
838  }
839 
840  private:
841  void move(Future&& that)
842  {
843  synchronized
844  {
845  memcpy(output_buffer_, that.output_buffer_, sizeof(OUT));
846  memcpy(input_buffer_, that.input_buffer_, sizeof(IN));
847  move_(std::move(that), sizeof(OUT), sizeof(IN));
848  }
849  }
850 
851  union
852  {
853  OUT output_;
854  uint8_t output_buffer_[sizeof(OUT)];
855  };
856  union
857  {
858  IN input_;
859  uint8_t input_buffer_[sizeof(IN)];
860  };
861  };
862 
863  // Future template specializations for void types
864  //================================================
866  template<typename OUT_>
867  class Future<OUT_, void> : public AbstractFuture
868  {
869  static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
870 
871  public:
872  using OUT = OUT_;
873  using IN = void;
874 
875  static constexpr uint8_t OUT_SIZE = sizeof(OUT);
876  static constexpr uint8_t IN_SIZE = 0;
877 
878  Future(STATUS_LISTENER* status_listener = nullptr, OUTPUT_LISTENER* output_listener = nullptr)
879  : AbstractFuture{output_buffer_, sizeof(OUT), nullptr, 0, status_listener, output_listener} {}
880  ~Future() = default;
881 
882  Future(Future&& that) : AbstractFuture{output_buffer_, sizeof(OUT), nullptr, 0}
883  {
884  move(std::move(that));
885  }
886  Future& operator=(Future&& that)
887  {
888  if (this == &that) return *this;
889  move(std::move(that));
890  return *this;
891  }
892 
893  Future(const Future&) = delete;
894  Future& operator=(const Future&) = delete;
895 
896  // This method completely resets this future (for reuse from scratch)
897  void reset_()
898  {
899  AbstractFuture::reset_(output_buffer_, sizeof(OUT), nullptr, 0);
900  }
901 
902  // The following method is blocking until this Future is ready
903  bool get(OUT& result)
904  {
905  if (await() != FutureStatus::READY)
906  return false;
907  result = output_;
908  return true;
909  }
910 
911  private:
912  void move(Future&& that)
913  {
914  synchronized
915  {
916  memcpy(output_buffer_, that.output_buffer_, sizeof(OUT));
917  move_(std::move(that), sizeof(OUT), 0);
918  }
919  }
920 
921  union
922  {
923  OUT output_;
924  uint8_t output_buffer_[sizeof(OUT)];
925  };
926  };
928 
930  template<typename IN_>
931  class Future<void, IN_> : public AbstractFuture
932  {
933  static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
934 
935  public:
936  using OUT = void;
937  using IN = IN_;
938 
939  static constexpr uint8_t OUT_SIZE = 0;
940  static constexpr uint8_t IN_SIZE = sizeof(IN);
941 
942  explicit Future(const IN& input = IN{}, STATUS_LISTENER* status_listener = nullptr)
943  : AbstractFuture{nullptr, 0, input_buffer_, sizeof(IN), status_listener}, input_{input} {}
944  ~Future() = default;
945 
946  Future(Future&& that) : AbstractFuture{nullptr, 0, input_buffer_, sizeof(IN)}
947  {
948  move(std::move(that));
949  }
950  Future& operator=(Future&& that)
951  {
952  if (this == &that) return *this;
953  move(std::move(that));
954  return *this;
955  }
956 
957  Future(const Future&) = delete;
958  Future& operator=(const Future&) = delete;
959 
960  // This method completely resets this future (for reuse from scratch)
961  void reset_(const IN& input = IN{})
962  {
963  AbstractFuture::reset_(nullptr, 0, input_buffer_, sizeof(IN));
964  input_ = input;
965  }
966 
967  bool reset_input_(const IN& input)
968  {
969  if (!can_replace_input_()) return false;
970  input_ = input;
971  return true;
972  }
973 
974  // The following method is blocking until this Future is ready
975  bool get()
976  {
977  return (await() == FutureStatus::READY);
978  }
979 
980  protected:
981  const IN& get_input() const
982  {
983  return input_;
984  }
985  IN& get_input()
986  {
987  return input_;
988  }
989 
990  private:
991  void move(Future&& that)
992  {
993  synchronized
994  {
995  memcpy(input_buffer_, that.input_buffer_, sizeof(IN));
996  move_(std::move(that), 0, sizeof(IN));
997  }
998  }
999 
1000  union
1001  {
1002  IN input_;
1003  uint8_t input_buffer_[sizeof(IN)];
1004  };
1005  };
1007 
1009  template<>
1010  class Future<void, void> : public AbstractFuture
1011  {
1012  public:
1013  using OUT = void;
1014  using IN = void;
1015 
1016  static constexpr uint8_t OUT_SIZE = 0;
1017  static constexpr uint8_t IN_SIZE = 0;
1018 
1019  explicit Future(STATUS_LISTENER* status_listener = nullptr)
1020  : AbstractFuture{nullptr, 0,nullptr, 0, status_listener} {}
1021  ~Future() = default;
1022 
1023  Future(Future&& that) : AbstractFuture{nullptr, 0, nullptr, 0}
1024  {
1025  synchronized move_(std::move(that), 0, 0);
1026  }
1027  Future& operator=(Future&& that)
1028  {
1029  if (this == &that) return *this;
1030  synchronized move_(std::move(that), 0, 0);
1031  return *this;
1032  }
1033 
1034  Future(const Future&) = delete;
1035  Future& operator=(const Future&) = delete;
1036 
1037  // This method completely resets this future (for reuse from scratch)
1038  void reset_()
1039  {
1040  AbstractFuture::reset_(nullptr, 0, nullptr, 0);
1041  }
1042 
1043  // The following method is blocking until this Future is ready
1044  bool get()
1045  {
1046  return (await() == FutureStatus::READY);
1047  }
1048  };
1050 
1062  {
1063  public:
1065  FutureStatus status() const
1066  {
1067  return (error_ == 0 ? FutureStatus::READY : FutureStatus::ERROR);
1068  }
1069 
1070  FutureStatus await() const
1071  {
1072  return status();
1073  }
1074 
1075  int error() const
1076  {
1077  return error_;
1078  }
1079 
1080  // Methods called by a Future consumer
1081  //=====================================
1082 
1083  uint8_t get_storage_value_size_() const
1084  {
1085  return input_size_;
1086  }
1087 
1088  bool get_storage_value_(uint8_t& chunk)
1089  {
1090  // Check all bytes have not been transferred yet
1091  chunk = *input_current_++;
1092  --input_size_;
1093  return true;
1094  }
1095 
1096  bool get_storage_value_(uint8_t* chunk, uint8_t size)
1097  {
1098  memcpy(chunk, input_current_, size);
1099  input_current_ += size;
1100  input_size_ -= size;
1101  return true;
1102  }
1103 
1104  // Methods called by a Future supplier
1105  //=====================================
1106 
1107  uint8_t get_future_value_size_() const
1108  {
1109  return output_size_;
1110  }
1111 
1112  bool set_future_finish_()
1113  {
1114  callback_status();
1115  return true;
1116  }
1117 
1118  bool set_future_value_(uint8_t chunk)
1119  {
1120  // Update Future value chunk
1121  *output_current_++ = chunk;
1122  --output_size_;
1123  callback_output();
1124  return true;
1125  }
1126 
1127  bool set_future_value_(const uint8_t* chunk, uint8_t size)
1128  {
1129  while (size--)
1130  {
1131  set_future_value_(*chunk++);
1132  }
1133  return true;
1134  }
1135 
1136  template<typename T> bool set_future_value_(const T& value)
1137  {
1138  return set_future_value_(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
1139  }
1140 
1141  bool set_future_error_(int error)
1142  {
1143  error_ = error;
1144  callback_status();
1145  return true;
1146  }
1147 
1148  using STATUS_LISTENER = FutureStatusListener<AbstractFakeFuture>;
1149  using OUTPUT_LISTENER = FutureOutputListener<AbstractFakeFuture>;
1151 
1152  protected:
1154  // "default" constructor
1155  AbstractFakeFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
1156  STATUS_LISTENER* status_listener = nullptr, OUTPUT_LISTENER* output_listener = nullptr)
1157  : output_current_{output_data}, output_size_{output_size},
1158  input_current_{input_data}, input_size_{input_size},
1159  status_listener_{status_listener}, output_listener_{output_listener} {}
1160 
1161  // these constructors are forbidden (subclass ctors shall call above move/copy ctor instead)
1162  AbstractFakeFuture(const AbstractFakeFuture&) = delete;
1163  AbstractFakeFuture& operator=(const AbstractFakeFuture&) = delete;
1165  AbstractFakeFuture& operator=(AbstractFakeFuture&&) = delete;
1166 
1167  ~AbstractFakeFuture() = default;
1168 
1169  // This method is called by subclasses to completely reset this future (for reuse from scratch)
1170  void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
1171  {
1172  error_ = 0;
1173  output_current_ = output_data;
1174  output_size_ = output_size;
1175  input_current_ = input_data;
1176  input_size_ = input_size;
1177  }
1178 
1179  // This method is called by subclass to check if input is replaceable,
1180  // i.e. it has not been read yet
1181  bool can_replace_input_() const
1182  {
1183  return true;
1184  }
1186 
1187  private:
1188  void callback_status()
1189  {
1190  if (status_listener_ != nullptr)
1191  status_listener_->on_status_change(*this, status());
1192  }
1193 
1194  void callback_output()
1195  {
1196  if (output_listener_ != nullptr)
1197  output_listener_->on_output_change(*this, nullptr, output_current_);
1198  }
1199 
1200  int error_ = 0;
1201 
1202  uint8_t* output_current_ = nullptr;
1203  uint8_t output_size_ = 0;
1204 
1205  uint8_t* input_current_ = nullptr;
1206  uint8_t input_size_ = 0;
1207 
1208  STATUS_LISTENER* status_listener_ = nullptr;
1209  OUTPUT_LISTENER* output_listener_ = nullptr;
1210 
1211  template<typename F> friend class AbstractFuturesGroup;
1212  };
1213 
1221  template<typename OUT_ = void, typename IN_ = void>
1223  {
1224  static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
1225  static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
1226 
1227  public:
1229  using OUT = OUT_;
1230  using IN = IN_;
1231 
1232  static constexpr uint8_t OUT_SIZE = sizeof(OUT);
1233  static constexpr uint8_t IN_SIZE = sizeof(IN);
1234 
1235  explicit FakeFuture(const IN& input = IN{},
1236  STATUS_LISTENER* status_listener = nullptr, OUTPUT_LISTENER* output_listener = nullptr)
1237  : AbstractFakeFuture{output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN),
1238  status_listener, output_listener}, input_{input} {}
1239 
1240  ~FakeFuture() = default;
1241 
1242  // This method completely resets this future (for reuse from scratch)
1243  void reset_(const IN& input = IN{})
1244  {
1245  AbstractFakeFuture::reset_(output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN));
1246  input_ = input;
1247  }
1248 
1249  bool reset_input_(const IN& input)
1250  {
1251  input_ = input;
1252  return true;
1253  }
1254 
1255  bool get(OUT& result)
1256  {
1257  result = output_;
1258  return true;
1259  }
1260 
1261  protected:
1262  const IN& get_input() const
1263  {
1264  return input_;
1265  }
1266  IN& get_input()
1267  {
1268  return input_;
1269  }
1271 
1272  private:
1273  union
1274  {
1275  OUT output_;
1276  uint8_t output_buffer_[sizeof(OUT)];
1277  };
1278  union
1279  {
1280  IN input_;
1281  uint8_t input_buffer_[sizeof(IN)];
1282  };
1283  };
1284 
1286  template<typename OUT_>
1287  class FakeFuture<OUT_, void> : public AbstractFakeFuture
1288  {
1289  static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
1290 
1291  public:
1292  using OUT = OUT_;
1293  using IN = void;
1294 
1295  static constexpr uint8_t OUT_SIZE = sizeof(OUT);
1296  static constexpr uint8_t IN_SIZE = 0;
1297 
1298  explicit FakeFuture(STATUS_LISTENER* status_listener = nullptr, OUTPUT_LISTENER* output_listener = nullptr)
1299  : AbstractFakeFuture{output_buffer_, sizeof(OUT), nullptr, 0,
1300  status_listener, output_listener} {}
1301 
1302  ~FakeFuture() = default;
1303 
1304  // This method completely resets this future (for reuse from scratch)
1305  void reset_()
1306  {
1307  AbstractFakeFuture::reset_(output_buffer_, sizeof(OUT), nullptr, 0);
1308  }
1309 
1310  bool get(OUT& result)
1311  {
1312  result = output_;
1313  return true;
1314  }
1315 
1316  private:
1317  union
1318  {
1319  OUT output_;
1320  uint8_t output_buffer_[sizeof(OUT)];
1321  };
1322  };
1324 
1326  template<typename IN_>
1327  class FakeFuture<void, IN_> : public AbstractFakeFuture
1328  {
1329  static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
1330 
1331  public:
1332  using OUT = void;
1333  using IN = IN_;
1334 
1335  static constexpr uint8_t OUT_SIZE = 0;
1336  static constexpr uint8_t IN_SIZE = sizeof(IN);
1337 
1338  explicit FakeFuture(const IN& input = IN{}, STATUS_LISTENER* status_listener = nullptr)
1339  : AbstractFakeFuture{nullptr, 0, input_buffer_, sizeof(IN), status_listener}, input_{input} {}
1340 
1341  ~FakeFuture() = default;
1342 
1343  // This method completely resets this future (for reuse from scratch)
1344  void reset_(const IN& input = IN{})
1345  {
1346  AbstractFakeFuture::reset_(nullptr, 0, input_buffer_, sizeof(IN));
1347  input_ = input;
1348  }
1349 
1350  bool reset_input_(const IN& input)
1351  {
1352  input_ = input;
1353  return true;
1354  }
1355 
1356  bool get()
1357  {
1358  return true;
1359  }
1360 
1361  protected:
1362  const IN& get_input() const
1363  {
1364  return input_;
1365  }
1366  IN& get_input()
1367  {
1368  return input_;
1369  }
1370 
1371  private:
1372  union
1373  {
1374  IN input_;
1375  uint8_t input_buffer_[sizeof(IN)];
1376  };
1377  };
1379 
1381  template<>
1382  class FakeFuture<void, void> : public AbstractFakeFuture
1383  {
1384  public:
1385  using OUT = void;
1386  using IN = void;
1387 
1388  static constexpr uint8_t OUT_SIZE = 0;
1389  static constexpr uint8_t IN_SIZE = 0;
1390 
1391  explicit FakeFuture(STATUS_LISTENER* status_listener = nullptr)
1392  : AbstractFakeFuture{nullptr, 0, nullptr, 0, status_listener} {}
1393 
1394  ~FakeFuture() = default;
1395 
1396  void reset_()
1397  {
1398  AbstractFakeFuture::reset_(nullptr, 0, nullptr, 0);
1399  }
1400 
1401  bool get()
1402  {
1403  return true;
1404  }
1405  };
1407 
1409  // Specific traits for futures
1410  template<typename F> struct Future_trait
1411  {
1412  static constexpr const bool IS_FUTURE = false;
1413  static constexpr const bool IS_ABSTRACT = false;
1414  static constexpr const bool IS_FAKE = false;
1415  };
1416  template<> struct Future_trait<AbstractFuture>
1417  {
1418  static constexpr const bool IS_FUTURE = true;
1419  static constexpr const bool IS_ABSTRACT = true;
1420  static constexpr const bool IS_FAKE = false;
1421  };
1422  template<typename OUT, typename IN> struct Future_trait<Future<OUT, IN>>
1423  {
1424  static constexpr const bool IS_FUTURE = true;
1425  static constexpr const bool IS_ABSTRACT = false;
1426  static constexpr const bool IS_FAKE = false;
1427  };
1428  template<> struct Future_trait<AbstractFakeFuture>
1429  {
1430  static constexpr const bool IS_FUTURE = true;
1431  static constexpr const bool IS_ABSTRACT = true;
1432  static constexpr const bool IS_FAKE = true;
1433  };
1434  template<typename OUT, typename IN> struct Future_trait<FakeFuture<OUT, IN>>
1435  {
1436  static constexpr const bool IS_FUTURE = true;
1437  static constexpr const bool IS_ABSTRACT = false;
1438  static constexpr const bool IS_FAKE = true;
1439  };
1441 
1473  template<typename F> class AbstractFuturesGroup : public F, public FutureStatusListener<F>
1474  {
1475  static_assert(Future_trait<F>::IS_FUTURE, "F must be a Future");
1476  static_assert(Future_trait<F>::IS_ABSTRACT, "F must be an abstract Future");
1477 
1478  public:
1484 
1485  protected:
1491  static constexpr const uint16_t NO_LIMIT = 0xFFFFU;
1492 
1507  explicit AbstractFuturesGroup(STATUS_LISTENER* status_listener = nullptr)
1508  : F{nullptr, 0, nullptr, 0, status_listener} {}
1509 
1524  void init(utils::range<F*> futures, uint16_t actual_size = 0)
1525  {
1526  num_ready_ = (actual_size != 0 ? actual_size : futures.size());
1527  for (F* future: futures)
1528  future->status_listener_ = this;
1529  }
1532  AbstractFuturesGroup& operator=(AbstractFuturesGroup&&) = delete;
1533  AbstractFuturesGroup(const AbstractFuturesGroup&) = delete;
1534  AbstractFuturesGroup& operator=(const AbstractFuturesGroup&) = delete;
1535 
1536  void on_status_change(const F& future, FutureStatus status) override
1537  {
1538  switch (status)
1539  {
1540  case FutureStatus::ERROR:
1541  this->set_future_error_(future.error());
1542  break;
1543 
1544  case FutureStatus::INVALID:
1545  this->set_future_error_(errors::EINVAL);
1546  break;
1547 
1548  case FutureStatus::READY:
1549  if (--num_ready_ == 0)
1550  this->set_future_finish_();
1551  break;
1552 
1553  default:
1554  break;
1555  }
1556  }
1558 
1559  private:
1560  uint16_t num_ready_ = 0;
1561  };
1562 }
1563 
1564 #endif /* FUTURE_HH */
1565 
future::FutureStatus::NOT_READY
@ NOT_READY
The status of a Future immediately after it has been constructed.
future::AbstractFuture::get_future_value_size_
uint8_t get_future_value_size_() const
Check the number of bytes remaining to write to the output value of this Future.
Definition: future.h:388
future
Contains the API around Future implementation.
Definition: future.cpp:18
future::AbstractFuture::STATUS_LISTENER
FutureStatusListener< AbstractFuture > STATUS_LISTENER
The type to use for status listeners for this type of Future.
Definition: future.h:573
future::FutureOutputListener
Listener is the interface allowing to listen to changes of a Future output buffer (while being fed by...
Definition: future.h:200
streams::ostream
Output stream wrapper to provide formatted output API, a la C++.
Definition: streams.h:61
std::move
constexpr types_traits::remove_reference< T >::type && move(T &&t)
Obtain an "rvalue" reference.
Definition: move.h:40
streams.h
C++-like std::iostream facilities.
errors::EMSGSIZE
constexpr const int EMSGSIZE
Message too long.
Definition: errors.h:68
future::Future::get_input
const IN & get_input() const
Return the input storage value as it was initially set (or reset through reset_input_()),...
Definition: future.h:825
future::FutureStatus::READY
@ READY
The status of a Future once its output value has been fully set by a provider.
future::AbstractFuture
Base class for all Futures.
Definition: future.h:223
future::AbstractFuture::set_future_finish_
bool set_future_finish_()
Mark this Future as FutureStatus::READY.
Definition: future.h:413
future::Future
Represent a value to be obtained, in some asynchronous way, in the future.
Definition: future.h:702
future::Future::get
bool get(OUT &result)
Wait until an output value has been completely filled in this Future and return that value to the cal...
Definition: future.h:811
future::Future::get_input
IN & get_input()
Return the input storage value as it was initially set (or reset through reset_input_()),...
Definition: future.h:835
future::FakeFuture
Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future.
Definition: future.h:1223
time::yield
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...
Definition: time.cpp:22
errors.h
Common errors definition.
future::Future::reset_input_
bool reset_input_(const IN &input)
Reset the input storage value held by this Future with a new value.
Definition: future.h:784
future::AbstractFuture::get_storage_value_size_
uint8_t get_storage_value_size_() const
Check the number of bytes remaining to read from this Future.
Definition: future.h:294
future::AbstractFuture::get_storage_value_
bool get_storage_value_(uint8_t &chunk)
Get one byte from the input storage value of this Future.
Definition: future.h:323
future::AbstractFuturesGroup::init
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...
Definition: future.h:1524
future::Future::Future
Future(const IN &input=IN{}, STATUS_LISTENER *status_listener=nullptr, OUTPUT_LISTENER *output_listener=nullptr)
Construct a new Future.
Definition: future.h:734
future::FutureStatus
FutureStatus
Status of a Future.
Definition: future.h:119
future::AbstractFuturesGroup::NO_LIMIT
static constexpr const uint16_t NO_LIMIT
Specific size value indicating this group has an unlimited (and unknown at construction time) number ...
Definition: future.h:1491
time.h
Simple time utilities.
future::FutureStatusListener
Listener is the interface allowing to listen to changes of a Future status.
Definition: future.h:176
future::AbstractFuture::set_future_value_
bool set_future_value_(const T &value)
Set the output value content of this Future.
Definition: future.h:536
iterator.h
Utilities to convert arrays into an iterable (usable if for x: list construct).
future::AbstractFuturesGroup::AbstractFuturesGroup
AbstractFuturesGroup(STATUS_LISTENER *status_listener=nullptr)
Construct a new AbstractFuturesGroup.
Definition: future.h:1507
errors::EINVAL
constexpr const int EINVAL
Invalid argument or invalid Future.
Definition: errors.h:49
future::Future::OUT_SIZE
static constexpr uint8_t OUT_SIZE
Size of the output value of this Future.
Definition: future.h:713
future::AbstractFuturesGroup
Abstract class to allow aggregation of several futures.
Definition: future.h:1474
future::Future::OUT
OUT_ OUT
Type of the output value of this Future.
Definition: future.h:708
future::FutureOutputListener::on_output_change
virtual void on_output_change(const F &future, uint8_t *output_data, uint8_t *output_current)=0
Called whenever a listened-to Future has its output buffer changed.
utils::range
Iterable class that can embed arrays or initializer lists through implicit conversion.
Definition: iterator.h:51
future::Future::IN_SIZE
static constexpr uint8_t IN_SIZE
Size of the input value of this Future.
Definition: future.h:715
future::AbstractFuture::set_future_value_
bool set_future_value_(const uint8_t *chunk, uint8_t size)
Add several bytes to the output value content of this Future.
Definition: future.h:495
future::FutureStatusListener::on_status_change
virtual void on_status_change(const F &future, FutureStatus new_status)=0
Called whenever a listened-to Future changes its FutureStatus.
future::AbstractFuture::status
FutureStatus status() const
The current status of this Future.
Definition: future.h:230
future::AbstractFakeFuture
Base class for all FakeFutures.
Definition: future.h:1062
future::AbstractFuture::set_future_error_
bool set_future_error_(int error)
Mark this Future as FutureStatus::ERROR.
Definition: future.h:558
future::AbstractFuture::set_future_value_
bool set_future_value_(uint8_t chunk)
Add one byte to the output value content of this Future.
Definition: future.h:450
future::Future::IN
IN_ IN
Type of the input value of this Future.
Definition: future.h:710
future::AbstractFuture::error
int error() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error,...
Definition: future.h:262
future::Future::reset_
void reset_(const IN &input=IN{})
This method completely resets this future (for reuse from scratch), as if it was just constructed.
Definition: future.h:764
F
#define F(ptr)
Force string constant to be stored as flash storage.
Definition: flash.h:118
future::AbstractFuture::OUTPUT_LISTENER
FutureOutputListener< AbstractFuture > OUTPUT_LISTENER
The type to use for output listeners for this type of Future.
Definition: future.h:579
future::AbstractFuture::get_storage_value_
bool get_storage_value_(uint8_t *chunk, uint8_t size)
Get size bytes from the input storage value of this Future.
Definition: future.h:359
future::AbstractFuture::await
FutureStatus await() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error.
Definition: future.h:244