map.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include <rpl/producer.h>
  9. namespace rpl {
  10. namespace details {
  11. template <
  12. typename Transform,
  13. typename NewValue,
  14. typename Error,
  15. typename Handlers>
  16. class map_transform_helper {
  17. public:
  18. map_transform_helper(
  19. Transform &&transform,
  20. const consumer<NewValue, Error, Handlers> &consumer)
  21. : _consumer(consumer)
  22. , _transform(std::move(transform)) {
  23. }
  24. template <
  25. typename OtherValue,
  26. typename = std::enable_if_t<
  27. std::is_rvalue_reference_v<OtherValue&&>>>
  28. void operator()(OtherValue &&value) const {
  29. _consumer.put_next_forward(
  30. details::callable_invoke(_transform, std::move(value)));
  31. }
  32. template <
  33. typename OtherValue,
  34. typename = decltype(
  35. std::declval<Transform>()(const_ref_val<OtherValue>()))>
  36. void operator()(const OtherValue &value) const {
  37. _consumer.put_next_forward(
  38. details::callable_invoke(_transform, value));
  39. }
  40. private:
  41. consumer<NewValue, Error, Handlers> _consumer;
  42. Transform _transform;
  43. };
  44. template <
  45. typename Transform,
  46. typename NewValue,
  47. typename Error,
  48. typename Handlers,
  49. typename = std::enable_if_t<
  50. std::is_rvalue_reference_v<Transform&&>>>
  51. inline map_transform_helper<Transform, NewValue, Error, Handlers>
  52. map_transform(
  53. Transform &&transform,
  54. const consumer<NewValue, Error, Handlers> &consumer) {
  55. return { std::move(transform), consumer };
  56. }
  57. template <typename Transform>
  58. class map_helper {
  59. public:
  60. template <typename OtherTransform>
  61. map_helper(OtherTransform &&transform)
  62. : _transform(std::forward<OtherTransform>(transform)) {
  63. }
  64. template <
  65. typename Value,
  66. typename Error,
  67. typename Generator,
  68. typename NewValue = details::callable_result<
  69. Transform,
  70. Value>>
  71. auto operator()(producer<Value, Error, Generator> &&initial) {
  72. return make_producer<NewValue, Error>([
  73. initial = std::move(initial),
  74. transform = std::move(_transform)
  75. ](const auto &consumer) mutable {
  76. return std::move(initial).start(
  77. map_transform(
  78. std::move(transform),
  79. consumer
  80. ), [consumer](auto &&error) {
  81. consumer.put_error_forward(
  82. std::forward<decltype(error)>(error));
  83. }, [consumer] {
  84. consumer.put_done();
  85. });
  86. });
  87. }
  88. private:
  89. Transform _transform;
  90. };
  91. } // namespace details
  92. template <typename Transform>
  93. inline auto map(Transform &&transform)
  94. -> details::map_helper<std::decay_t<Transform>> {
  95. return details::map_helper<std::decay_t<Transform>>(
  96. std::forward<Transform>(transform));
  97. }
  98. template <typename Value>
  99. [[nodiscard]] inline auto map_to(Value &&value) {
  100. return map([value = std::forward<Value>(value)] {
  101. return value;
  102. });
  103. }
  104. inline auto to_empty = map_to(empty_value());
  105. namespace details {
  106. template <
  107. typename Transform,
  108. typename Value,
  109. typename NewError,
  110. typename Handlers>
  111. class map_error_transform_helper {
  112. public:
  113. map_error_transform_helper(
  114. Transform &&transform,
  115. const consumer<Value, NewError, Handlers> &consumer)
  116. : _transform(std::move(transform))
  117. , _consumer(consumer) {
  118. }
  119. template <
  120. typename OtherError,
  121. typename = std::enable_if_t<
  122. std::is_rvalue_reference_v<OtherError&&>>>
  123. void operator()(OtherError &&error) const {
  124. _consumer.put_error_forward(
  125. details::callable_invoke(_transform, std::move(error)));
  126. }
  127. template <
  128. typename OtherError,
  129. typename = decltype(
  130. std::declval<Transform>()(const_ref_val<OtherError>()))>
  131. void operator()(const OtherError &error) const {
  132. _consumer.put_error_forward(
  133. details::callable_invoke(_transform, error));
  134. }
  135. private:
  136. consumer<Value, NewError, Handlers> _consumer;
  137. Transform _transform;
  138. };
  139. template <
  140. typename Transform,
  141. typename Value,
  142. typename NewError,
  143. typename Handlers,
  144. typename = std::enable_if_t<
  145. std::is_rvalue_reference_v<Transform&&>>>
  146. inline map_error_transform_helper<Transform, Value, NewError, Handlers>
  147. map_error_transform(
  148. Transform &&transform,
  149. const consumer<Value, NewError, Handlers> &consumer) {
  150. return { std::move(transform), consumer };
  151. }
  152. template <typename Transform>
  153. class map_error_helper {
  154. public:
  155. template <typename OtherTransform>
  156. map_error_helper(OtherTransform &&transform)
  157. : _transform(std::forward<OtherTransform>(transform)) {
  158. }
  159. template <
  160. typename Value,
  161. typename Error,
  162. typename Generator,
  163. typename NewError = details::callable_result<
  164. Transform,
  165. Error>>
  166. auto operator()(producer<Value, Error, Generator> &&initial) {
  167. return make_producer<Value, NewError>([
  168. initial = std::move(initial),
  169. transform = std::move(_transform)
  170. ](const auto &consumer) mutable {
  171. return std::move(initial).start(
  172. [consumer](auto &&value) {
  173. consumer.put_next_forward(
  174. std::forward<decltype(value)>(value));
  175. }, map_error_transform(
  176. std::move(transform),
  177. consumer
  178. ), [consumer] {
  179. consumer.put_done();
  180. });
  181. });
  182. }
  183. private:
  184. Transform _transform;
  185. };
  186. class map_error_to_done_helper {
  187. public:
  188. map_error_to_done_helper() {
  189. }
  190. template <
  191. typename Value,
  192. typename Error,
  193. typename Generator>
  194. auto operator()(producer<Value, Error, Generator> &&initial) {
  195. return make_producer<Value, no_error>([
  196. initial = std::move(initial)
  197. ](const auto &consumer) mutable {
  198. return std::move(initial).start(
  199. [consumer](auto &&value) {
  200. consumer.put_next_forward(
  201. std::forward<decltype(value)>(value));
  202. }, [consumer] {
  203. consumer.put_done();
  204. }, [consumer] {
  205. consumer.put_done();
  206. });
  207. });
  208. }
  209. };
  210. } // namespace details
  211. template <typename Transform>
  212. inline auto map_error(Transform &&transform)
  213. -> details::map_error_helper<std::decay_t<Transform>> {
  214. return details::map_error_helper<std::decay_t<Transform>>(
  215. std::forward<Transform>(transform));
  216. }
  217. inline details::map_error_to_done_helper map_error_to_done() {
  218. return details::map_error_to_done_helper();
  219. }
  220. } // namespace rpl