mirror of https://github.com/procxx/kepka.git
Allow not type-erased producers.
This commit is contained in:
parent
086e46c162
commit
cdda7f8f9a
|
@ -185,11 +185,12 @@ SectionWithToggle *SectionWithToggle::setToggleShown(
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> SectionWithToggle::toggledValue() const {
|
rpl::producer<bool> SectionWithToggle::toggledValue() const {
|
||||||
return _toggle
|
if (_toggle) {
|
||||||
? (rpl::single(_toggle->checked())
|
return rpl::single(_toggle->checked())
|
||||||
| rpl::then(
|
| rpl::then(
|
||||||
base::ObservableViewer(_toggle->checkedChanged)))
|
base::ObservableViewer(_toggle->checkedChanged));
|
||||||
: rpl::never<bool>();
|
}
|
||||||
|
return rpl::never<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> SectionWithToggle::toggleShownValue() const {
|
rpl::producer<bool> SectionWithToggle::toggleShownValue() const {
|
||||||
|
|
|
@ -432,7 +432,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupUserActions(
|
||||||
st::infoBlockButtonSkip));
|
st::infoBlockButtonSkip));
|
||||||
|
|
||||||
auto text = PeerUpdateValue(user, Notify::PeerUpdate::Flag::UserIsBlocked)
|
auto text = PeerUpdateValue(user, Notify::PeerUpdate::Flag::UserIsBlocked)
|
||||||
| rpl::map([user](auto&&) {
|
| rpl::map([user](auto&&) -> rpl::producer<QString> {
|
||||||
switch (user->blockStatus()) {
|
switch (user->blockStatus()) {
|
||||||
case UserData::BlockStatus::Blocked:
|
case UserData::BlockStatus::Blocked:
|
||||||
return Lang::Viewer(lng_profile_unblock_user);
|
return Lang::Viewer(lng_profile_unblock_user);
|
||||||
|
|
|
@ -33,10 +33,9 @@ public:
|
||||||
: _method(std::forward<OtherSideEffect>(method)) {
|
: _method(std::forward<OtherSideEffect>(method)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
rpl::producer<Value, Error> operator()(
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
rpl::producer<Value, Error> &&initial) {
|
return make_producer<Value, Error>([
|
||||||
return [
|
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
method = std::move(_method)
|
method = std::move(_method)
|
||||||
](const consumer<Value, Error> &consumer) mutable {
|
](const consumer<Value, Error> &consumer) mutable {
|
||||||
|
@ -52,7 +51,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -58,8 +58,8 @@ public:
|
||||||
, _state(state) {
|
, _state(state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
void subscribe(producer<Value, Error> &&producer) {
|
void subscribe(producer<Value, Error, Generator> &&producer) {
|
||||||
_consumer.add_lifetime(std::move(producer).start(
|
_consumer.add_lifetime(std::move(producer).start(
|
||||||
[consumer = _consumer, state = _state](Value &&value) {
|
[consumer = _consumer, state = _state](Value &&value) {
|
||||||
if (!state->accumulated) {
|
if (!state->accumulated) {
|
||||||
|
@ -101,12 +101,13 @@ template <
|
||||||
typename consumer_type,
|
typename consumer_type,
|
||||||
typename ...Values,
|
typename ...Values,
|
||||||
typename ...Errors,
|
typename ...Errors,
|
||||||
|
typename ...Generators,
|
||||||
std::size_t ...I>
|
std::size_t ...I>
|
||||||
inline void combine_subscribe(
|
inline void combine_subscribe(
|
||||||
const consumer_type &consumer,
|
const consumer_type &consumer,
|
||||||
combine_state<Values...> *state,
|
combine_state<Values...> *state,
|
||||||
std::index_sequence<I...>,
|
std::index_sequence<I...>,
|
||||||
producer<Values, Errors> &&...producers) {
|
producer<Values, Errors, Generators> &&...producers) {
|
||||||
auto consume = { (
|
auto consume = { (
|
||||||
details::combine_subscribe_one<
|
details::combine_subscribe_one<
|
||||||
I,
|
I,
|
||||||
|
@ -119,17 +120,18 @@ inline void combine_subscribe(
|
||||||
(void)consume;
|
(void)consume;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ...Values, typename ...Errors>
|
template <
|
||||||
|
typename ...Values,
|
||||||
|
typename ...Errors,
|
||||||
|
typename ...Generators>
|
||||||
inline auto combine_implementation(
|
inline auto combine_implementation(
|
||||||
producer<Values, Errors> &&...producers) {
|
producer<Values, Errors, Generators> &&...producers) {
|
||||||
|
using CombinedValue = std::tuple<Values...>;
|
||||||
using CombinedError = details::normalized_variant_t<Errors...>;
|
using CombinedError = details::normalized_variant_t<Errors...>;
|
||||||
using Result = producer<
|
using consumer_type = consumer<CombinedValue, CombinedError>;
|
||||||
std::tuple<Values...>,
|
|
||||||
CombinedError>;
|
|
||||||
using consumer_type = typename Result::consumer_type;
|
|
||||||
auto result = [](
|
auto result = [](
|
||||||
const consumer_type &consumer,
|
const consumer_type &consumer,
|
||||||
producer<Values, Errors> &...producers) {
|
producer<Values, Errors, Generators> &...producers) {
|
||||||
auto state = consumer.template make_state<
|
auto state = consumer.template make_state<
|
||||||
details::combine_state<Values...>>();
|
details::combine_state<Values...>>();
|
||||||
|
|
||||||
|
@ -142,7 +144,7 @@ inline auto combine_implementation(
|
||||||
|
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
};
|
||||||
return Result(std::bind(
|
return make_producer<CombinedValue, CombinedError>(std::bind(
|
||||||
result,
|
result,
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::move(producers)...));
|
std::move(producers)...));
|
||||||
|
@ -156,8 +158,12 @@ template <typename ...Args>
|
||||||
constexpr bool combine_just_producers_v
|
constexpr bool combine_just_producers_v
|
||||||
= combine_just_producers<Args...>::value;
|
= combine_just_producers<Args...>::value;
|
||||||
|
|
||||||
template <typename ...Values, typename ...Errors>
|
template <
|
||||||
struct combine_just_producers<producer<Values, Errors>...>
|
typename ...Values,
|
||||||
|
typename ...Errors,
|
||||||
|
typename ...Generators>
|
||||||
|
struct combine_just_producers<
|
||||||
|
producer<Values, Errors, Generators>...>
|
||||||
: std::true_type {
|
: std::true_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,8 +179,11 @@ template <typename ...Args>
|
||||||
using combine_result_type_t
|
using combine_result_type_t
|
||||||
= typename combine_result_type<Args...>::type;
|
= typename combine_result_type<Args...>::type;
|
||||||
|
|
||||||
template <typename ...Values, typename ...Errors>
|
template <
|
||||||
struct combine_result_type<producer<Values, Errors>...> {
|
typename ...Values,
|
||||||
|
typename ...Errors,
|
||||||
|
typename ...Generators>
|
||||||
|
struct combine_result_type<producer<Values, Errors, Generators>...> {
|
||||||
using type = std::tuple<Values...>;
|
using type = std::tuple<Values...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,10 +231,13 @@ template <typename ...Args>
|
||||||
constexpr bool combine_producers_with_mapper_v
|
constexpr bool combine_producers_with_mapper_v
|
||||||
= combine_producers_with_mapper<Args...>::value;
|
= combine_producers_with_mapper<Args...>::value;
|
||||||
|
|
||||||
template <typename ...Values, typename ...Errors>
|
template <
|
||||||
|
typename ...Values,
|
||||||
|
typename ...Errors,
|
||||||
|
typename ...Generators>
|
||||||
inline decltype(auto) combine_helper(
|
inline decltype(auto) combine_helper(
|
||||||
std::true_type,
|
std::true_type,
|
||||||
producer<Values, Errors> &&...producers) {
|
producer<Values, Errors, Generators> &&...producers) {
|
||||||
return combine_implementation(std::move(producers)...);
|
return combine_implementation(std::move(producers)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,17 +286,14 @@ struct combine_vector_state {
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
inline producer<std::vector<Value>, Error> combine(
|
inline auto combine(
|
||||||
std::vector<producer<Value, Error>> &&producers) {
|
std::vector<producer<Value, Error, Generator>> &&producers) {
|
||||||
if (producers.empty()) {
|
|
||||||
return complete<std::vector<Value>, Error>();
|
|
||||||
}
|
|
||||||
|
|
||||||
using state_type = details::combine_vector_state<Value>;
|
using state_type = details::combine_vector_state<Value>;
|
||||||
using consumer_type = consumer<std::vector<Value>, Error>;
|
using consumer_type = consumer<std::vector<Value>, Error>;
|
||||||
return [producers = std::move(producers)](
|
return make_producer<std::vector<Value>, Error>([
|
||||||
const consumer_type &consumer) mutable {
|
producers = std::move(producers)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
auto count = producers.size();
|
auto count = producers.size();
|
||||||
auto state = consumer.template make_state<state_type>();
|
auto state = consumer.template make_state<state_type>();
|
||||||
state->accumulated.resize(count);
|
state->accumulated.resize(count);
|
||||||
|
@ -320,13 +329,20 @@ inline producer<std::vector<Value>, Error> combine(
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
if (!count) {
|
||||||
|
consumer.put_done();
|
||||||
|
}
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error, typename Mapper>
|
template <
|
||||||
|
typename Value,
|
||||||
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
|
typename Mapper>
|
||||||
inline auto combine(
|
inline auto combine(
|
||||||
std::vector<producer<Value, Error>> &&producers,
|
std::vector<producer<Value, Error, Generator>> &&producers,
|
||||||
Mapper &&mapper) {
|
Mapper &&mapper) {
|
||||||
return combine(std::move(producers))
|
return combine(std::move(producers))
|
||||||
| map(std::forward<Mapper>(mapper));
|
| map(std::forward<Mapper>(mapper));
|
||||||
|
|
|
@ -28,14 +28,15 @@ namespace details {
|
||||||
|
|
||||||
class combine_previous_helper {
|
class combine_previous_helper {
|
||||||
public:
|
public:
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
rpl::producer<std::tuple<Value, Value>, Error> operator()(
|
auto operator()(
|
||||||
rpl::producer<Value, Error> &&initial) const {
|
producer<Value, Error, Generator> &&initial) const {
|
||||||
using consumer_type = consumer<
|
using consumer_type = consumer<
|
||||||
std::tuple<Value, Value>,
|
std::tuple<Value, Value>,
|
||||||
Error>;
|
Error>;
|
||||||
return [initial = std::move(initial)](
|
return make_producer<std::tuple<Value, Value>, Error>([
|
||||||
const consumer_type &consumer) mutable {
|
initial = std::move(initial)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
auto previous = consumer.template make_state<
|
auto previous = consumer.template make_state<
|
||||||
base::optional<Value>
|
base::optional<Value>
|
||||||
>();
|
>();
|
||||||
|
@ -58,7 +59,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -71,13 +72,12 @@ public:
|
||||||
: _value(std::forward<OtherValue>(value)) {
|
: _value(std::forward<OtherValue>(value)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
rpl::producer<std::tuple<Value, Value>, Error> operator()(
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
rpl::producer<Value, Error> &&initial) {
|
|
||||||
using consumer_type = consumer<
|
using consumer_type = consumer<
|
||||||
std::tuple<Value, Value>,
|
std::tuple<Value, Value>,
|
||||||
Error>;
|
Error>;
|
||||||
return [
|
return make_producer<std::tuple<Value, Value>, Error>([
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
value = Value(std::move(_value))
|
value = Value(std::move(_value))
|
||||||
](const consumer_type &consumer) mutable {
|
](const consumer_type &consumer) mutable {
|
||||||
|
@ -96,7 +96,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -25,11 +25,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
|
||||||
template <typename Value = empty_value, typename Error = no_error>
|
template <typename Value = empty_value, typename Error = no_error>
|
||||||
inline producer<Value, Error> complete() {
|
inline auto complete() {
|
||||||
return [](const consumer<Value, Error> &consumer) mutable {
|
return make_producer<Value, Error>([](
|
||||||
|
const consumer<Value, Error> &consumer) {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -28,11 +28,12 @@ template <
|
||||||
typename Creator,
|
typename Creator,
|
||||||
typename Value = typename decltype(std::declval<Creator>()())::value_type,
|
typename Value = typename decltype(std::declval<Creator>()())::value_type,
|
||||||
typename Error = typename decltype(std::declval<Creator>()())::error_type>
|
typename Error = typename decltype(std::declval<Creator>()())::error_type>
|
||||||
inline producer<Value, Error> deferred(Creator &&creator) {
|
inline auto deferred(Creator &&creator) {
|
||||||
return [creator = std::forward<Creator>(creator)](
|
return make_producer<Value, Error>([
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
creator = std::forward<Creator>(creator)
|
||||||
|
](const consumer<Value, Error> &consumer) mutable {
|
||||||
return std::move(creator)().start_existing(consumer);
|
return std::move(creator)().start_existing(consumer);
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace rpl {
|
||||||
|
|
||||||
|
template <typename Value1, typename Value2>
|
||||||
|
struct superset_type;
|
||||||
|
|
||||||
|
template <typename Value1, typename Value2>
|
||||||
|
using superset_type_t = typename superset_type<Value1, Value2>::type;
|
||||||
|
|
||||||
|
template <typename Value>
|
||||||
|
struct superset_type<Value, Value> {
|
||||||
|
using type = Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rpl
|
|
@ -28,11 +28,12 @@ namespace details {
|
||||||
|
|
||||||
class distinct_until_changed_helper {
|
class distinct_until_changed_helper {
|
||||||
public:
|
public:
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
rpl::producer<Value, Error> operator()(
|
auto operator()(
|
||||||
rpl::producer<Value, Error> &&initial) const {
|
producer<Value, Error, Generator> &&initial) const {
|
||||||
return [initial = std::move(initial)](
|
return make_producer<Value, Error>([
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
initial = std::move(initial)
|
||||||
|
](const consumer<Value, Error> &consumer) mutable {
|
||||||
auto previous = consumer.template make_state<
|
auto previous = consumer.template make_state<
|
||||||
base::optional<Value>
|
base::optional<Value>
|
||||||
>();
|
>();
|
||||||
|
@ -47,7 +48,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,13 +46,29 @@ public:
|
||||||
void fire_copy(const Value &value) const {
|
void fire_copy(const Value &value) const {
|
||||||
return fire_forward(value);
|
return fire_forward(value);
|
||||||
}
|
}
|
||||||
producer<Value, no_error> events() const;
|
auto events() const {
|
||||||
producer<Value, no_error> events_starting_with(
|
using consumer_type = consumer<Value, no_error>;
|
||||||
Value &&value) const {
|
return make_producer<Value>([weak = weak()](
|
||||||
|
const consumer_type &consumer) {
|
||||||
|
if (auto strong = weak.lock()) {
|
||||||
|
auto result = [weak, consumer] {
|
||||||
|
if (auto strong = weak.lock()) {
|
||||||
|
auto it = base::find(*strong, consumer);
|
||||||
|
if (it != strong->end()) {
|
||||||
|
it->terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
strong->push_back(std::move(consumer));
|
||||||
|
return lifetime(std::move(result));
|
||||||
|
}
|
||||||
|
return lifetime();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
auto events_starting_with(Value &&value) const {
|
||||||
return single(std::move(value)) | then(events());
|
return single(std::move(value)) | then(events());
|
||||||
}
|
}
|
||||||
producer<Value, no_error> events_starting_with_copy(
|
auto events_starting_with_copy(const Value &value) const {
|
||||||
const Value &value) const {
|
|
||||||
return single(value) | then(events());
|
return single(value) | then(events());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,26 +133,6 @@ inline void event_stream<Value>::fire_forward(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value>
|
|
||||||
inline producer<Value, no_error> event_stream<Value>::events() const {
|
|
||||||
return producer<Value, no_error>([weak = weak()](
|
|
||||||
const consumer<Value, no_error> &consumer) {
|
|
||||||
if (auto strong = weak.lock()) {
|
|
||||||
auto result = [weak, consumer] {
|
|
||||||
if (auto strong = weak.lock()) {
|
|
||||||
auto it = base::find(*strong, consumer);
|
|
||||||
if (it != strong->end()) {
|
|
||||||
it->terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
strong->push_back(std::move(consumer));
|
|
||||||
return lifetime(std::move(result));
|
|
||||||
}
|
|
||||||
return lifetime();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
inline std::weak_ptr<std::vector<consumer<Value, no_error>>> event_stream<Value>::weak() const {
|
inline std::weak_ptr<std::vector<consumer<Value, no_error>>> event_stream<Value>::weak() const {
|
||||||
if (!_consumers) {
|
if (!_consumers) {
|
||||||
|
@ -171,9 +167,9 @@ public:
|
||||||
start_spawning_helper(lifetime &alive_while)
|
start_spawning_helper(lifetime &alive_while)
|
||||||
: _lifetime(alive_while) {
|
: _lifetime(alive_while) {
|
||||||
}
|
}
|
||||||
template <typename Value, typename Error>
|
|
||||||
producer<Value, Error> operator()(
|
template <typename Value, typename Error, typename Generator>
|
||||||
producer<Value, Error> &&initial) {
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
auto stream = _lifetime.make_state<event_stream<Value>>();
|
auto stream = _lifetime.make_state<event_stream<Value>>();
|
||||||
auto collected = std::vector<Value>();
|
auto collected = std::vector<Value>();
|
||||||
{
|
{
|
||||||
|
@ -185,9 +181,7 @@ public:
|
||||||
[] {});
|
[] {});
|
||||||
std::move(initial) | start_to_stream(*stream, _lifetime);
|
std::move(initial) | start_to_stream(*stream, _lifetime);
|
||||||
}
|
}
|
||||||
return collected.empty()
|
return vector(std::move(collected))
|
||||||
? stream->events()
|
|
||||||
: vector(std::move(collected))
|
|
||||||
| then(stream->events());
|
| then(stream->events());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error>
|
||||||
inline producer<Value, std::decay_t<Error>> fail(Error &&error) {
|
inline auto fail(Error &&error) {
|
||||||
using consumer_t = consumer<Value, std::decay_t<Error>>;
|
using consumer_t = consumer<Value, std::decay_t<Error>>;
|
||||||
return [error = std::forward<Error>(error)](
|
return make_producer<Value, std::decay_t<Error>>([
|
||||||
const consumer_t &consumer) mutable {
|
error = std::forward<Error>(error)
|
||||||
|
](const consumer_t &consumer) mutable {
|
||||||
consumer.put_error(std::move(error));
|
consumer.put_error(std::move(error));
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include <rpl/producer.h>
|
#include <rpl/producer.h>
|
||||||
#include <rpl/combine.h>
|
#include <rpl/combine.h>
|
||||||
|
#include <rpl/mappers.h>
|
||||||
#include "base/optional.h"
|
#include "base/optional.h"
|
||||||
|
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
@ -38,15 +39,15 @@ public:
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
details::is_callable_v<Predicate, Value>>>
|
details::is_callable_v<Predicate, Value>>>
|
||||||
rpl::producer<Value, Error> operator()(
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
rpl::producer<Value, Error> &&initial) {
|
using consumer_type = consumer<Value, Error>;
|
||||||
return [
|
return make_producer<Value, Error>([
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
predicate = std::move(_predicate)
|
predicate = std::move(_predicate)
|
||||||
](
|
](const consumer_type &consumer) mutable {
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
|
||||||
return std::move(initial).start(
|
return std::move(initial).start(
|
||||||
[
|
[
|
||||||
consumer,
|
consumer,
|
||||||
|
@ -66,7 +67,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -85,27 +86,24 @@ inline auto filter(Predicate &&predicate)
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template <>
|
template <typename FilterError, typename FilterGenerator>
|
||||||
class filter_helper<producer<bool>> {
|
class filter_helper<producer<bool, FilterError, FilterGenerator>> {
|
||||||
public:
|
public:
|
||||||
filter_helper(producer<bool> &&filterer)
|
filter_helper(
|
||||||
: _filterer(std::move(filterer)) {
|
producer<bool, FilterError, FilterGenerator> &&filterer)
|
||||||
|
: _filterer(std::move(filterer)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <typename Value, typename Error, typename Generator>
|
||||||
typename Value,
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
typename Error>
|
using namespace mappers;
|
||||||
rpl::producer<Value, Error> operator()(
|
|
||||||
rpl::producer<Value, Error> &&initial) {
|
|
||||||
return combine(std::move(initial), std::move(_filterer))
|
return combine(std::move(initial), std::move(_filterer))
|
||||||
| filter([](auto &&value, bool let) { return let; })
|
| filter($2)
|
||||||
| map([](auto &&value, bool) {
|
| map($1_of_two);
|
||||||
return std::forward<decltype(value)>(value);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
producer<bool> _filterer;
|
producer<bool, FilterError, FilterGenerator> _filterer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,12 +121,15 @@ inline Value &&deref_optional_helper(
|
||||||
|
|
||||||
class filter_optional_helper {
|
class filter_optional_helper {
|
||||||
public:
|
public:
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
rpl::producer<Value, Error> operator()(
|
auto operator()(producer<
|
||||||
rpl::producer<base::optional<Value>, Error> &&initial
|
base::optional<Value>,
|
||||||
) const {
|
Error,
|
||||||
return [initial = std::move(initial)](
|
Generator> &&initial) const {
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
using consumer_type = consumer<Value, Error>;
|
||||||
|
return make_producer<Value, Error>([
|
||||||
|
initial = std::move(initial)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
return std::move(initial).start(
|
return std::move(initial).start(
|
||||||
[consumer](auto &&value) {
|
[consumer](auto &&value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -143,7 +144,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,17 +27,22 @@ namespace details {
|
||||||
|
|
||||||
class flatten_latest_helper {
|
class flatten_latest_helper {
|
||||||
public:
|
public:
|
||||||
template <typename Value, typename Error>
|
template <
|
||||||
rpl::producer<Value, Error> operator()(
|
typename Value,
|
||||||
rpl::producer<
|
typename Error,
|
||||||
rpl::producer<Value, Error>,
|
typename Generator,
|
||||||
Error
|
typename MetaGenerator>
|
||||||
> &&initial) const {
|
auto operator()(producer<
|
||||||
return [initial = std::move(initial)](
|
producer<Value, Error, Generator>,
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
Error,
|
||||||
|
MetaGenerator> &&initial) const {
|
||||||
|
using consumer_type = consumer<Value, Error>;
|
||||||
|
return make_producer<Value, Error>([
|
||||||
|
initial = std::move(initial)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
auto state = std::make_shared<State>();
|
auto state = std::make_shared<State>();
|
||||||
return std::move(initial).start(
|
return std::move(initial).start(
|
||||||
[consumer, state](rpl::producer<Value, Error> &&inner) {
|
[consumer, state](producer<Value, Error> &&inner) {
|
||||||
state->finished = false;
|
state->finished = false;
|
||||||
state->alive = std::move(inner).start(
|
state->alive = std::move(inner).start(
|
||||||
[consumer](auto &&value) {
|
[consumer](auto &&value) {
|
||||||
|
@ -60,7 +65,7 @@ public:
|
||||||
state->finished = true;
|
state->finished = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -84,12 +84,12 @@ public:
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename NewValue = details::callable_result<
|
typename NewValue = details::callable_result<
|
||||||
Transform,
|
Transform,
|
||||||
Value>>
|
Value>>
|
||||||
rpl::producer<NewValue, Error> operator()(
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
rpl::producer<Value, Error> &&initial) {
|
return make_producer<NewValue, Error>([
|
||||||
return [
|
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
transform = std::move(_transform)
|
transform = std::move(_transform)
|
||||||
](const consumer<NewValue, Error> &consumer) mutable {
|
](const consumer<NewValue, Error> &consumer) mutable {
|
||||||
|
@ -103,7 +103,7 @@ public:
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -181,12 +181,12 @@ public:
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename NewError = details::callable_result<
|
typename NewError = details::callable_result<
|
||||||
Transform,
|
Transform,
|
||||||
Error>>
|
Error>>
|
||||||
rpl::producer<Value, NewError> operator()(
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
||||||
rpl::producer<Value, Error> &&initial) {
|
return make_producer<Value, NewError>([
|
||||||
return [
|
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
transform = std::move(_transform)
|
transform = std::move(_transform)
|
||||||
](const consumer<Value, NewError> &consumer) mutable {
|
](const consumer<Value, NewError> &consumer) mutable {
|
||||||
|
@ -200,7 +200,7 @@ public:
|
||||||
), [consumer] {
|
), [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -501,5 +501,7 @@ inline auto $val(Type &&value) {
|
||||||
return details::make_value_mapper(std::forward<Type>(value));
|
return details::make_value_mapper(std::forward<Type>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr const auto $1_of_two = ((void)$2, $1);
|
||||||
|
|
||||||
} // namespace mappers
|
} // namespace mappers
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -25,10 +25,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
|
||||||
template <typename Value = empty_value, typename Error = no_error>
|
template <typename Value = empty_value, typename Error = no_error>
|
||||||
inline producer<Value, Error> never() {
|
inline auto never() {
|
||||||
return [](const consumer<Value, Error> &consumer) mutable {
|
using consumer_type = consumer<Value, Error>;
|
||||||
|
return make_producer<Value, Error>([](
|
||||||
|
const consumer_type &consumer) {
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -123,7 +123,7 @@ TEST_CASE("basic operators tests", "[rpl::operators]") {
|
||||||
auto copyCount = std::make_shared<int>(0);
|
auto copyCount = std::make_shared<int>(0);
|
||||||
auto moveCount = std::make_shared<int>(0);
|
auto moveCount = std::make_shared<int>(0);
|
||||||
{
|
{
|
||||||
auto testing = complete<InvokeCounter>();
|
auto testing = complete<InvokeCounter>() | type_erased();
|
||||||
for (auto i = 0; i != 5; ++i) {
|
for (auto i = 0; i != 5; ++i) {
|
||||||
InvokeCounter counter(copyCount, moveCount);
|
InvokeCounter counter(copyCount, moveCount);
|
||||||
testing = std::move(testing)
|
testing = std::move(testing)
|
||||||
|
@ -248,8 +248,18 @@ TEST_CASE("basic operators tests", "[rpl::operators]") {
|
||||||
| start_with_next([=](std::string &&value) {
|
| start_with_next([=](std::string &&value) {
|
||||||
*sum += std::move(value) + ' ';
|
*sum += std::move(value) + ' ';
|
||||||
}, lifetime);
|
}, lifetime);
|
||||||
|
single(single(1))
|
||||||
|
| then(single(single(2) | then(single(3))))
|
||||||
|
| then(single(single(4) | then(single(5)) | then(single(6))))
|
||||||
|
| flatten_latest()
|
||||||
|
| map([](int value) {
|
||||||
|
return std::to_string(value);
|
||||||
|
})
|
||||||
|
| start_with_next([=](std::string &&value) {
|
||||||
|
*sum += std::move(value) + ' ';
|
||||||
|
}, lifetime);
|
||||||
}
|
}
|
||||||
REQUIRE(*sum == "1 2 3 4 5 6 ");
|
REQUIRE(*sum == "1 2 3 4 5 6 1 2 3 4 5 6 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("combine vector test") {
|
SECTION("combine vector test") {
|
||||||
|
@ -363,4 +373,19 @@ TEST_CASE("basic operators tests", "[rpl::operators]") {
|
||||||
}
|
}
|
||||||
REQUIRE(*sum == "16192225");
|
REQUIRE(*sum == "16192225");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("after_next test") {
|
||||||
|
auto sum = std::make_shared<std::string>("");
|
||||||
|
{
|
||||||
|
rpl::lifetime lifetime;
|
||||||
|
rpl::ints(3)
|
||||||
|
| after_next([=](int value) {
|
||||||
|
*sum += std::to_string(-value-1);
|
||||||
|
})
|
||||||
|
| start_with_next([=](int value) {
|
||||||
|
*sum += std::to_string(value);
|
||||||
|
}, lifetime);
|
||||||
|
}
|
||||||
|
REQUIRE(*sum == "0-11-22-3");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,27 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "base/lambda.h"
|
#include "base/lambda.h"
|
||||||
#include <rpl/consumer.h>
|
#include <rpl/consumer.h>
|
||||||
#include <rpl/lifetime.h>
|
#include <rpl/lifetime.h>
|
||||||
|
#include <rpl/details/superset_type.h>
|
||||||
|
#include <rpl/details/callable.h>
|
||||||
|
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
|
template <typename Value, typename Error>
|
||||||
|
const consumer<Value, Error> &const_ref_consumer();
|
||||||
|
|
||||||
template <typename Lambda>
|
template <typename Lambda>
|
||||||
class mutable_lambda_wrap {
|
class mutable_lambda_wrap {
|
||||||
public:
|
public:
|
||||||
mutable_lambda_wrap(Lambda &&lambda)
|
mutable_lambda_wrap(Lambda &&lambda)
|
||||||
: _lambda(std::move(lambda)) {
|
: _lambda(std::move(lambda)) {
|
||||||
}
|
}
|
||||||
|
mutable_lambda_wrap(const mutable_lambda_wrap &other) = default;
|
||||||
|
mutable_lambda_wrap(mutable_lambda_wrap &&other) = default;
|
||||||
|
mutable_lambda_wrap &operator=(
|
||||||
|
const mutable_lambda_wrap &other) = default;
|
||||||
|
mutable_lambda_wrap &operator=(
|
||||||
|
mutable_lambda_wrap &&other) = default;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto operator()(Args&&... args) const {
|
auto operator()(Args&&... args) const {
|
||||||
|
@ -46,62 +57,134 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type-erased copyable mutable lambda using base::lambda.
|
// Type-erased copyable mutable lambda using base::lambda.
|
||||||
template <typename Function> class mutable_lambda;
|
template <typename Value, typename Error>
|
||||||
|
class type_erased_generator final {
|
||||||
template <typename Return, typename ...Args>
|
|
||||||
class mutable_lambda<Return(Args...)> {
|
|
||||||
public:
|
public:
|
||||||
|
using value_type = Value;
|
||||||
|
using error_type = Error;
|
||||||
|
using consumer_type = consumer<Value, Error>;
|
||||||
|
|
||||||
|
type_erased_generator(
|
||||||
|
const type_erased_generator &other) = default;
|
||||||
|
type_erased_generator(
|
||||||
|
type_erased_generator &&other) = default;
|
||||||
|
type_erased_generator &operator=(
|
||||||
|
const type_erased_generator &other) = default;
|
||||||
|
type_erased_generator &operator=(
|
||||||
|
type_erased_generator &&other) = default;
|
||||||
|
|
||||||
// Copy / move construct / assign from an arbitrary type.
|
|
||||||
template <
|
template <
|
||||||
typename Lambda,
|
typename Generator,
|
||||||
typename = std::enable_if_t<std::is_convertible<
|
typename = std::enable_if_t<
|
||||||
decltype(std::declval<Lambda>()(
|
std::is_convertible_v<
|
||||||
std::declval<Args>()...)),
|
decltype(std::declval<Generator>()(
|
||||||
Return
|
const_ref_consumer<Value, Error>())),
|
||||||
>::value>>
|
lifetime> &&
|
||||||
mutable_lambda(Lambda other) : _implementation(
|
!std::is_same_v<
|
||||||
mutable_lambda_wrap<Lambda>(std::move(other))) {
|
std::decay_t<Generator>,
|
||||||
|
type_erased_generator>>>
|
||||||
|
type_erased_generator(Generator other) : _implementation(
|
||||||
|
mutable_lambda_wrap<Generator>(std::move(other))) {
|
||||||
|
}
|
||||||
|
template <
|
||||||
|
typename Generator,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible_v<
|
||||||
|
decltype(std::declval<Generator>()(
|
||||||
|
const_ref_consumer<Value, Error>())),
|
||||||
|
lifetime> &&
|
||||||
|
!std::is_same_v<
|
||||||
|
std::decay_t<Generator>,
|
||||||
|
type_erased_generator>>>
|
||||||
|
type_erased_generator &operator=(Generator other) {
|
||||||
|
_implementation = mutable_lambda_wrap<Generator>(
|
||||||
|
std::move(other));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
lifetime operator()(const consumer_type &consumer) {
|
||||||
typename ...OtherArgs,
|
return _implementation(consumer);
|
||||||
typename = std::enable_if_t<
|
|
||||||
(sizeof...(Args) == sizeof...(OtherArgs))>>
|
|
||||||
Return operator()(OtherArgs&&... args) {
|
|
||||||
return _implementation(std::forward<OtherArgs>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base::lambda<Return(Args...)> _implementation;
|
base::lambda<lifetime(const consumer_type &)> _implementation;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
template <typename Value = empty_value, typename Error = no_error>
|
template <
|
||||||
class producer {
|
typename Value = empty_value,
|
||||||
|
typename Error = no_error,
|
||||||
|
typename Generator = details::type_erased_generator<
|
||||||
|
Value,
|
||||||
|
Error>>
|
||||||
|
class producer;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Value1,
|
||||||
|
typename Value2,
|
||||||
|
typename Error1,
|
||||||
|
typename Error2,
|
||||||
|
typename Generator>
|
||||||
|
struct superset_type<
|
||||||
|
producer<Value1, Error1, Generator>,
|
||||||
|
producer<Value2, Error2, Generator>> {
|
||||||
|
using type = producer<
|
||||||
|
superset_type_t<Value1, Value2>,
|
||||||
|
superset_type_t<Error1, Error2>,
|
||||||
|
Generator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Value,
|
||||||
|
typename Error,
|
||||||
|
typename Generator1,
|
||||||
|
typename Generator2>
|
||||||
|
struct superset_type<
|
||||||
|
producer<Value, Error, Generator1>,
|
||||||
|
producer<Value, Error, Generator2>> {
|
||||||
|
using type = producer<Value, Error>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Value,
|
||||||
|
typename Error,
|
||||||
|
typename Generator>
|
||||||
|
struct superset_type<
|
||||||
|
producer<Value, Error, Generator>,
|
||||||
|
producer<Value, Error, Generator>> {
|
||||||
|
using type = producer<Value, Error, Generator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template <typename Value, typename Error, typename Generator>
|
||||||
|
class producer_base {
|
||||||
public:
|
public:
|
||||||
using value_type = Value;
|
using value_type = Value;
|
||||||
using error_type = Error;
|
using error_type = Error;
|
||||||
using consumer_type = consumer<Value, Error>;
|
using consumer_type = consumer<Value, Error>;
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename Generator,
|
typename OtherGenerator,
|
||||||
typename = std::enable_if<std::is_convertible<
|
typename = std::enable_if_t<
|
||||||
decltype(std::declval<Generator>()(
|
std::is_constructible_v<Generator, OtherGenerator&&>>>
|
||||||
std::declval<consumer_type>())),
|
producer_base(OtherGenerator &&generator);
|
||||||
lifetime>::value>>
|
|
||||||
producer(Generator &&generator);
|
producer_base(const producer_base &other) = default;
|
||||||
|
producer_base(producer_base &&other) = default;
|
||||||
|
producer_base &operator=(const producer_base &other) = default;
|
||||||
|
producer_base &operator=(producer_base &&other) = default;
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
details::is_callable_v<OnNext, Value>
|
is_callable_v<OnNext, Value>
|
||||||
&& details::is_callable_v<OnError, Error>
|
&& is_callable_v<OnError, Error>
|
||||||
&& details::is_callable_v<OnDone>>>
|
&& is_callable_v<OnDone>>>
|
||||||
lifetime start(
|
lifetime start(
|
||||||
OnNext &&next,
|
OnNext &&next,
|
||||||
OnError &&error,
|
OnError &&error,
|
||||||
|
@ -112,9 +195,9 @@ public:
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
details::is_callable_v<OnNext, Value>
|
is_callable_v<OnNext, Value>
|
||||||
&& details::is_callable_v<OnError, Error>
|
&& is_callable_v<OnError, Error>
|
||||||
&& details::is_callable_v<OnDone>>>
|
&& is_callable_v<OnDone>>>
|
||||||
lifetime start_copy(
|
lifetime start_copy(
|
||||||
OnNext &&next,
|
OnNext &&next,
|
||||||
OnError &&error,
|
OnError &&error,
|
||||||
|
@ -123,24 +206,30 @@ public:
|
||||||
lifetime start_existing(const consumer_type &consumer) &&;
|
lifetime start_existing(const consumer_type &consumer) &&;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
details::mutable_lambda<
|
Generator _generator;
|
||||||
lifetime(const consumer_type &)> _generator;
|
|
||||||
|
template <
|
||||||
|
typename OtherValue,
|
||||||
|
typename OtherError,
|
||||||
|
typename OtherGenerator>
|
||||||
|
friend class ::rpl::producer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
template <typename Generator, typename>
|
template <typename OtherGenerator, typename>
|
||||||
inline producer<Value, Error>::producer(Generator &&generator)
|
inline producer_base<Value, Error, Generator>::producer_base(
|
||||||
: _generator(std::forward<Generator>(generator)) {
|
OtherGenerator &&generator)
|
||||||
|
: _generator(std::forward<OtherGenerator>(generator)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
template <
|
template <
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename>
|
typename>
|
||||||
inline lifetime producer<Value, Error>::start(
|
inline lifetime producer_base<Value, Error, Generator>::start(
|
||||||
OnNext &&next,
|
OnNext &&next,
|
||||||
OnError &&error,
|
OnError &&error,
|
||||||
OnDone &&done) && {
|
OnDone &&done) && {
|
||||||
|
@ -150,13 +239,13 @@ inline lifetime producer<Value, Error>::start(
|
||||||
std::forward<OnDone>(done)));
|
std::forward<OnDone>(done)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
template <
|
template <
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename>
|
typename>
|
||||||
inline lifetime producer<Value, Error>::start_copy(
|
inline lifetime producer_base<Value, Error, Generator>::start_copy(
|
||||||
OnNext &&next,
|
OnNext &&next,
|
||||||
OnError &&error,
|
OnError &&error,
|
||||||
OnDone &&done) const & {
|
OnDone &&done) const & {
|
||||||
|
@ -167,26 +256,122 @@ inline lifetime producer<Value, Error>::start_copy(
|
||||||
std::forward<OnDone>(done));
|
std::forward<OnDone>(done));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
inline lifetime producer<Value, Error>::start_existing(
|
inline lifetime producer_base<Value, Error, Generator>::start_existing(
|
||||||
const consumer_type &consumer) && {
|
const consumer_type &consumer) && {
|
||||||
consumer.add_lifetime(std::move(_generator)(consumer));
|
consumer.add_lifetime(std::move(_generator)(consumer));
|
||||||
return [consumer] { consumer.terminate(); };
|
return [consumer] { consumer.terminate(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error>
|
||||||
inline producer<Value, Error> duplicate(
|
using producer_base_type_erased = producer_base<
|
||||||
const producer<Value, Error> &value) {
|
Value,
|
||||||
|
Error,
|
||||||
|
type_erased_generator<Value, Error>>;
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
template <typename Value, typename Error, typename Generator>
|
||||||
|
class producer final
|
||||||
|
: public details::producer_base<Value, Error, Generator> {
|
||||||
|
using parent_type = details::producer_base<
|
||||||
|
Value,
|
||||||
|
Error,
|
||||||
|
Generator>;
|
||||||
|
public:
|
||||||
|
using parent_type::parent_type;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Value, typename Error>
|
||||||
|
class producer<
|
||||||
|
Value,
|
||||||
|
Error,
|
||||||
|
details::type_erased_generator<Value, Error>> final
|
||||||
|
: public details::producer_base_type_erased<Value, Error> {
|
||||||
|
using parent_type = details::producer_base_type_erased<
|
||||||
|
Value,
|
||||||
|
Error>;
|
||||||
|
public:
|
||||||
|
using parent_type::parent_type;;
|
||||||
|
|
||||||
|
producer(const producer &other) = default;
|
||||||
|
producer(producer &&other) = default;
|
||||||
|
producer &operator=(const producer &other) = default;
|
||||||
|
producer &operator=(producer &&other) = default;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Generic,
|
||||||
|
typename = std::enable_if_t<!std::is_same_v<
|
||||||
|
Generic,
|
||||||
|
details::type_erased_generator<Value, Error>>>>
|
||||||
|
producer(const details::producer_base<Value, Error, Generic> &other)
|
||||||
|
: parent_type(other._generator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Generic,
|
||||||
|
typename = std::enable_if_t<!std::is_same_v<
|
||||||
|
Generic,
|
||||||
|
details::type_erased_generator<Value, Error>>>>
|
||||||
|
producer(details::producer_base<Value, Error, Generic> &&other)
|
||||||
|
: parent_type(std::move(other._generator)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Generic,
|
||||||
|
typename = std::enable_if_t<!std::is_same_v<
|
||||||
|
Generic,
|
||||||
|
details::type_erased_generator<Value, Error>>>>
|
||||||
|
producer &operator=(
|
||||||
|
const details::producer_base<Value, Error, Generic> &other) {
|
||||||
|
this->_generator = other._generator;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Generic,
|
||||||
|
typename = std::enable_if_t<!std::is_same_v<
|
||||||
|
Generic,
|
||||||
|
details::type_erased_generator<Value, Error>>>>
|
||||||
|
producer &operator=(
|
||||||
|
details::producer_base<Value, Error, Generic> &&other) {
|
||||||
|
this->_generator = std::move(other._generator);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Value = empty_value,
|
||||||
|
typename Error = no_error,
|
||||||
|
typename Generator,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible_v<
|
||||||
|
decltype(std::declval<Generator>()(
|
||||||
|
details::const_ref_consumer<Value, Error>())),
|
||||||
|
lifetime>>>
|
||||||
|
inline auto make_producer(Generator &&generator)
|
||||||
|
-> producer<Value, Error, std::decay_t<Generator>> {
|
||||||
|
return std::forward<Generator>(generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Value, typename Error, typename Generator>
|
||||||
|
inline producer<Value, Error, Generator> duplicate(
|
||||||
|
const producer<Value, Error, Generator> &value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename Method,
|
typename Method,
|
||||||
typename = decltype(std::declval<Method>()(
|
typename = decltype(std::declval<Method>()(
|
||||||
std::declval<producer<Value, Error>>()))>
|
std::declval<producer<Value, Error, Generator>>()))>
|
||||||
inline auto operator|(producer<Value, Error> &&value, Method &&method) {
|
inline auto operator|(
|
||||||
|
producer<Value, Error, Generator> &&value,
|
||||||
|
Method &&method) {
|
||||||
return std::forward<Method>(method)(std::move(value));
|
return std::forward<Method>(method)(std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +518,9 @@ inline auto start_with_next_error_done(
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_none &&lifetime) {
|
lifetime_with_none &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -347,10 +532,11 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename = std::enable_if_t<is_callable_v<OnNext, Value>>>
|
typename = std::enable_if_t<is_callable_v<OnNext, Value>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_next<OnNext> &&lifetime) {
|
lifetime_with_next<OnNext> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -362,10 +548,11 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename = std::enable_if_t<is_callable_v<OnError, Error>>>
|
typename = std::enable_if_t<is_callable_v<OnError, Error>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_error<OnError> &&lifetime) {
|
lifetime_with_error<OnError> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -377,10 +564,11 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename = std::enable_if_t<is_callable_v<OnDone>>>
|
typename = std::enable_if_t<is_callable_v<OnDone>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_done<OnDone> &&lifetime) {
|
lifetime_with_done<OnDone> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -392,13 +580,14 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
is_callable_v<OnNext, Value> &&
|
is_callable_v<OnNext, Value> &&
|
||||||
is_callable_v<OnError, Error>>>
|
is_callable_v<OnError, Error>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_next_error<OnNext, OnError> &&lifetime) {
|
lifetime_with_next_error<OnNext, OnError> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -410,13 +599,14 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
is_callable_v<OnError, Error> &&
|
is_callable_v<OnError, Error> &&
|
||||||
is_callable_v<OnDone>>>
|
is_callable_v<OnDone>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_error_done<OnError, OnDone> &&lifetime) {
|
lifetime_with_error_done<OnError, OnDone> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -428,13 +618,14 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
is_callable_v<OnNext, Value> &&
|
is_callable_v<OnNext, Value> &&
|
||||||
is_callable_v<OnDone>>>
|
is_callable_v<OnDone>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_next_done<OnNext, OnDone> &&lifetime) {
|
lifetime_with_next_done<OnNext, OnDone> &&lifetime) {
|
||||||
lifetime.alive_while.add(
|
lifetime.alive_while.add(
|
||||||
std::move(value).start(
|
std::move(value).start(
|
||||||
|
@ -446,6 +637,7 @@ inline void operator|(
|
||||||
template <
|
template <
|
||||||
typename Value,
|
typename Value,
|
||||||
typename Error,
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename OnNext,
|
typename OnNext,
|
||||||
typename OnError,
|
typename OnError,
|
||||||
typename OnDone,
|
typename OnDone,
|
||||||
|
@ -454,7 +646,7 @@ template <
|
||||||
is_callable_v<OnError, Error> &&
|
is_callable_v<OnError, Error> &&
|
||||||
is_callable_v<OnDone>>>
|
is_callable_v<OnDone>>>
|
||||||
inline void operator|(
|
inline void operator|(
|
||||||
producer<Value, Error> &&value,
|
producer<Value, Error, Generator> &&value,
|
||||||
lifetime_with_next_error_done<
|
lifetime_with_next_error_done<
|
||||||
OnNext,
|
OnNext,
|
||||||
OnError,
|
OnError,
|
||||||
|
|
|
@ -52,7 +52,7 @@ TEST_CASE("basic producer tests", "[rpl::producer]") {
|
||||||
*destroyed = true;
|
*destroyed = true;
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
producer<int, no_error>([=](auto &&consumer) {
|
make_producer<int>([=](auto &&consumer) {
|
||||||
(void)destroyCaller;
|
(void)destroyCaller;
|
||||||
consumer.put_next(1);
|
consumer.put_next(1);
|
||||||
consumer.put_next(2);
|
consumer.put_next(2);
|
||||||
|
@ -82,7 +82,7 @@ TEST_CASE("basic producer tests", "[rpl::producer]") {
|
||||||
SECTION("producer error test") {
|
SECTION("producer error test") {
|
||||||
auto errorGenerated = std::make_shared<bool>(false);
|
auto errorGenerated = std::make_shared<bool>(false);
|
||||||
{
|
{
|
||||||
producer<no_value, bool>([=](auto &&consumer) {
|
make_producer<no_value, bool>([=](auto &&consumer) {
|
||||||
consumer.put_error(true);
|
consumer.put_error(true);
|
||||||
return lifetime();
|
return lifetime();
|
||||||
}).start([=](no_value) {
|
}).start([=](no_value) {
|
||||||
|
@ -99,7 +99,7 @@ TEST_CASE("basic producer tests", "[rpl::producer]") {
|
||||||
{
|
{
|
||||||
auto lifetimes = lifetime();
|
auto lifetimes = lifetime();
|
||||||
{
|
{
|
||||||
auto testProducer = producer<no_value, no_error>([=](auto &&consumer) {
|
auto testProducer = make_producer<no_value>([=](auto &&consumer) {
|
||||||
return [=] {
|
return [=] {
|
||||||
++*lifetimeEndCount;
|
++*lifetimeEndCount;
|
||||||
};
|
};
|
||||||
|
@ -123,8 +123,8 @@ TEST_CASE("basic producer tests", "[rpl::producer]") {
|
||||||
auto lifetimeEndCount = std::make_shared<int>(0);
|
auto lifetimeEndCount = std::make_shared<int>(0);
|
||||||
auto saved = lifetime();
|
auto saved = lifetime();
|
||||||
{
|
{
|
||||||
saved = producer<int, no_error>([=](auto &&consumer) {
|
saved = make_producer<int>([=](auto &&consumer) {
|
||||||
auto inner = producer<int, no_error>([=](auto &&consumer) {
|
auto inner = make_producer<int>([=](auto &&consumer) {
|
||||||
consumer.put_next(1);
|
consumer.put_next(1);
|
||||||
consumer.put_next(2);
|
consumer.put_next(2);
|
||||||
consumer.put_next(3);
|
consumer.put_next(3);
|
||||||
|
@ -161,7 +161,8 @@ TEST_CASE("basic producer tests", "[rpl::producer]") {
|
||||||
SECTION("tuple producer test") {
|
SECTION("tuple producer test") {
|
||||||
auto result = std::make_shared<int>(0);
|
auto result = std::make_shared<int>(0);
|
||||||
{
|
{
|
||||||
producer<std::tuple<int, double>>([=](auto &&consumer) {
|
make_producer<std::tuple<int, double>>([=](
|
||||||
|
auto &&consumer) {
|
||||||
consumer.put_next(std::make_tuple(1, 2.));
|
consumer.put_next(std::make_tuple(1, 2.));
|
||||||
return lifetime();
|
return lifetime();
|
||||||
}).start([=](int a, double b) {
|
}).start([=](int a, double b) {
|
||||||
|
@ -345,7 +346,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
auto dones = std::make_shared<int>(0);
|
auto dones = std::make_shared<int>(0);
|
||||||
{
|
{
|
||||||
auto alive = lifetime();
|
auto alive = lifetime();
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(1);
|
consumer.put_next(1);
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
|
@ -353,7 +354,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
*sum += value;
|
*sum += value;
|
||||||
}, alive);
|
}, alive);
|
||||||
|
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(11);
|
consumer.put_next(11);
|
||||||
consumer.put_error(111);
|
consumer.put_error(111);
|
||||||
return lifetime();
|
return lifetime();
|
||||||
|
@ -361,7 +362,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
*sum += value;
|
*sum += value;
|
||||||
}, alive);
|
}, alive);
|
||||||
|
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(1111);
|
consumer.put_next(1111);
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
|
@ -369,7 +370,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
*dones += 1;
|
*dones += 1;
|
||||||
}, alive);
|
}, alive);
|
||||||
|
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(11111);
|
consumer.put_next(11111);
|
||||||
consumer.put_next(11112);
|
consumer.put_next(11112);
|
||||||
consumer.put_next(11113);
|
consumer.put_next(11113);
|
||||||
|
@ -383,7 +384,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto alive = lifetime();
|
auto alive = lifetime();
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(111111);
|
consumer.put_next(111111);
|
||||||
consumer.put_next(111112);
|
consumer.put_next(111112);
|
||||||
consumer.put_next(111113);
|
consumer.put_next(111113);
|
||||||
|
@ -395,7 +396,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
*dones += 11;
|
*dones += 11;
|
||||||
}, alive);
|
}, alive);
|
||||||
|
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_error(1111111);
|
consumer.put_error(1111111);
|
||||||
return lifetime();
|
return lifetime();
|
||||||
}) | start_with_error_done([=](int value) {
|
}) | start_with_error_done([=](int value) {
|
||||||
|
@ -404,7 +405,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
*dones = 0;
|
*dones = 0;
|
||||||
}, alive);
|
}, alive);
|
||||||
|
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(11111111);
|
consumer.put_next(11111111);
|
||||||
consumer.put_next(11111112);
|
consumer.put_next(11111112);
|
||||||
consumer.put_next(11111113);
|
consumer.put_next(11111113);
|
||||||
|
@ -438,7 +439,7 @@ TEST_CASE("basic piping tests", "[rpl::producer]") {
|
||||||
|
|
||||||
for (int i = 0; i != 3; ++i) {
|
for (int i = 0; i != 3; ++i) {
|
||||||
auto alive = lifetime();
|
auto alive = lifetime();
|
||||||
producer<int, int>([=](auto &&consumer) {
|
make_producer<int, int>([=](auto &&consumer) {
|
||||||
consumer.put_next(1);
|
consumer.put_next(1);
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
|
|
|
@ -24,69 +24,78 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
|
||||||
template <typename Value, typename Error = no_error>
|
template <typename Value>
|
||||||
inline producer<std::decay_t<Value>, Error> single(Value &&value) {
|
inline auto single(Value &&value) {
|
||||||
using consumer_t = consumer<std::decay_t<Value>, Error>;
|
using consumer_type = consumer<std::decay_t<Value>, no_error>;
|
||||||
return [value = std::forward<Value>(value)](
|
return make_producer<std::decay_t<Value>>([
|
||||||
const consumer_t &consumer) mutable {
|
value = std::forward<Value>(value)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
consumer.put_next(std::move(value));
|
consumer.put_next(std::move(value));
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Error = no_error>
|
inline auto single() {
|
||||||
inline producer<empty_value, Error> single() {
|
using consumer_type = consumer<empty_value, no_error>;
|
||||||
return [](const consumer<empty_value, Error> &consumer) {
|
return make_producer<>([](
|
||||||
|
const consumer_type &consumer) {
|
||||||
consumer.put_next({});
|
consumer.put_next({});
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error = no_error>
|
template <typename Value>
|
||||||
inline producer<Value, Error> vector(std::vector<Value> &&values) {
|
inline auto vector(std::vector<Value> &&values) {
|
||||||
return [values = std::move(values)](
|
using consumer_type = consumer<Value, no_error>;
|
||||||
const consumer<Value, Error> &consumer) mutable {
|
return make_producer<Value>([
|
||||||
|
values = std::move(values)
|
||||||
|
](const consumer_type &consumer) mutable {
|
||||||
for (auto &value : values) {
|
for (auto &value : values) {
|
||||||
consumer.put_next(std::move(value));
|
consumer.put_next(std::move(value));
|
||||||
}
|
}
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Error = no_error>
|
inline auto vector(std::vector<bool> &&values) {
|
||||||
inline producer<bool, Error> vector(std::vector<bool> &&values) {
|
using consumer_type = consumer<bool, no_error>;
|
||||||
return [values = std::move(values)](
|
return make_producer<bool>([
|
||||||
const consumer<bool, Error> &consumer) mutable {
|
values = std::move(values)
|
||||||
|
](const consumer_type &consumer) {
|
||||||
for (auto value : values) {
|
for (auto value : values) {
|
||||||
consumer.put_next_copy(value);
|
consumer.put_next_copy(value);
|
||||||
}
|
}
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value, typename Error = no_error, typename Range>
|
template <
|
||||||
inline producer<Value, Error> range(Range &&range) {
|
typename Range,
|
||||||
|
typename Value = std::decay_t<
|
||||||
|
decltype(*std::begin(std::declval<Range>()))>>
|
||||||
|
inline auto range(Range &&range) {
|
||||||
return vector(std::vector<Value>(
|
return vector(std::vector<Value>(
|
||||||
std::begin(range),
|
std::begin(range),
|
||||||
std::end(range)));
|
std::end(range)));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline producer<int> ints(int from, int till) {
|
inline auto ints(int from, int till) {
|
||||||
Expects(from <= till);
|
Expects(from <= till);
|
||||||
return [from, till](const consumer<int> &consumer) {
|
return make_producer<int>([from, till](
|
||||||
|
const consumer<int> &consumer) {
|
||||||
for (auto i = from; i != till; ++i) {
|
for (auto i = from; i != till; ++i) {
|
||||||
consumer.put_next_copy(i);
|
consumer.put_next_copy(i);
|
||||||
}
|
}
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
return lifetime();
|
return lifetime();
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline producer<int> ints(int count) {
|
inline auto ints(int count) {
|
||||||
return ints(0, count);
|
return ints(0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include <rpl/mappers.h>
|
#include <rpl/mappers.h>
|
||||||
#include <rpl/filter.h>
|
#include <rpl/filter.h>
|
||||||
#include <rpl/distinct_until_changed.h>
|
#include <rpl/distinct_until_changed.h>
|
||||||
|
#include <rpl/type_erased.h>
|
||||||
#include <rpl/flatten_latest.h>
|
#include <rpl/flatten_latest.h>
|
||||||
#include <rpl/combine.h>
|
#include <rpl/combine.h>
|
||||||
#include <rpl/combine_previous.h>
|
#include <rpl/combine_previous.h>
|
||||||
|
|
|
@ -23,36 +23,64 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include <rpl/producer.h>
|
#include <rpl/producer.h>
|
||||||
|
|
||||||
namespace rpl {
|
namespace rpl {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
template <typename Value, typename Error>
|
template <typename Value, typename Error, typename Generator>
|
||||||
inline auto then(producer<Value, Error> &&following) {
|
class then_helper {
|
||||||
return [following = std::move(following)](
|
public:
|
||||||
producer<Value, Error> &&initial) mutable
|
then_helper(producer<Value, Error, Generator> &&following)
|
||||||
-> producer<Value, Error> {
|
: _following(std::move(following)) {
|
||||||
return [
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename OtherValue,
|
||||||
|
typename OtherError,
|
||||||
|
typename OtherGenerator,
|
||||||
|
typename NewValue = superset_type_t<Value, OtherValue>,
|
||||||
|
typename NewError = superset_type_t<Error, OtherError>>
|
||||||
|
auto operator()(
|
||||||
|
producer<OtherValue, OtherError, OtherGenerator> &&initial
|
||||||
|
) {
|
||||||
|
using consumer_type = consumer<NewValue, NewError>;
|
||||||
|
return make_producer<NewValue, NewError>([
|
||||||
initial = std::move(initial),
|
initial = std::move(initial),
|
||||||
following = std::move(following)
|
following = std::move(_following)
|
||||||
](const consumer<Value, Error> &consumer) mutable {
|
](const consumer_type &consumer) mutable {
|
||||||
return std::move(initial).start(
|
return std::move(initial).start(
|
||||||
[consumer](auto &&value) {
|
[consumer](auto &&value) {
|
||||||
consumer.put_next_forward(std::forward<decltype(value)>(value));
|
consumer.put_next_forward(
|
||||||
|
std::forward<decltype(value)>(value));
|
||||||
}, [consumer](auto &&error) {
|
}, [consumer](auto &&error) {
|
||||||
consumer.put_error_forward(std::forward<decltype(error)>(error));
|
consumer.put_error_forward(
|
||||||
|
std::forward<decltype(error)>(error));
|
||||||
}, [
|
}, [
|
||||||
consumer,
|
consumer,
|
||||||
following = std::move(following)
|
following = std::move(following)
|
||||||
]() mutable {
|
]() mutable {
|
||||||
consumer.add_lifetime(std::move(following).start(
|
consumer.add_lifetime(std::move(following).start(
|
||||||
[consumer](auto &&value) {
|
[consumer](auto &&value) {
|
||||||
consumer.put_next_forward(std::forward<decltype(value)>(value));
|
consumer.put_next_forward(
|
||||||
|
std::forward<decltype(value)>(value));
|
||||||
}, [consumer](auto &&error) {
|
}, [consumer](auto &&error) {
|
||||||
consumer.put_error_forward(std::forward<decltype(error)>(error));
|
consumer.put_error_forward(
|
||||||
|
std::forward<decltype(error)>(error));
|
||||||
}, [consumer] {
|
}, [consumer] {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
producer<Value, Error, Generator> _following;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
template <typename Value, typename Error, typename Generator>
|
||||||
|
inline auto then(producer<Value, Error, Generator> &&following)
|
||||||
|
-> details::then_helper<Value, Error, Generator> {
|
||||||
|
return { std::move(following) };
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rpl
|
} // namespace rpl
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <rpl/producer.h>
|
||||||
|
|
||||||
|
namespace rpl {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
class type_erased_helper {
|
||||||
|
public:
|
||||||
|
template <typename Value, typename Error, typename Generator>
|
||||||
|
producer<Value, Error> operator()(
|
||||||
|
producer<Value, Error, Generator> &&initial) const {
|
||||||
|
return std::move(initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
inline auto type_erased()
|
||||||
|
-> details::type_erased_helper {
|
||||||
|
return details::type_erased_helper();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rpl
|
|
@ -62,9 +62,11 @@ public:
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename OtherType,
|
typename OtherType,
|
||||||
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
std::is_assignable_v<Type, OtherType>>>
|
std::is_assignable_v<Type, OtherType>>>
|
||||||
variable(rpl::producer<OtherType> &&stream) {
|
variable(producer<OtherType, Error, Generator> &&stream) {
|
||||||
std::move(stream)
|
std::move(stream)
|
||||||
| start_with_next([this](auto &&data) {
|
| start_with_next([this](auto &&data) {
|
||||||
*this = std::forward<decltype(data)>(data);
|
*this = std::forward<decltype(data)>(data);
|
||||||
|
@ -73,9 +75,12 @@ public:
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename OtherType,
|
typename OtherType,
|
||||||
|
typename Error,
|
||||||
|
typename Generator,
|
||||||
typename = std::enable_if_t<
|
typename = std::enable_if_t<
|
||||||
std::is_assignable_v<Type, OtherType>>>
|
std::is_assignable_v<Type, OtherType>>>
|
||||||
variable &operator=(rpl::producer<OtherType> &&stream) {
|
variable &operator=(
|
||||||
|
producer<OtherType, Error, Generator> &&stream) {
|
||||||
_lifetime.destroy();
|
_lifetime.destroy();
|
||||||
std::move(stream)
|
std::move(stream)
|
||||||
| start_with_next([this](auto &&data) {
|
| start_with_next([this](auto &&data) {
|
||||||
|
@ -86,7 +91,7 @@ public:
|
||||||
Type current() const {
|
Type current() const {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
rpl::producer<Type> value() const {
|
auto value() const {
|
||||||
return _changes.events_starting_with_copy(_data);
|
return _changes.events_starting_with_copy(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +105,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
Type _data;
|
Type _data;
|
||||||
rpl::event_stream<Type> _changes;
|
event_stream<Type> _changes;
|
||||||
rpl::lifetime _lifetime;
|
lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'<(src_loc)/rpl/details/callable.h',
|
'<(src_loc)/rpl/details/callable.h',
|
||||||
|
'<(src_loc)/rpl/details/superset_type.h',
|
||||||
'<(src_loc)/rpl/details/type_list.h',
|
'<(src_loc)/rpl/details/type_list.h',
|
||||||
'<(src_loc)/rpl/after_next.h',
|
'<(src_loc)/rpl/after_next.h',
|
||||||
'<(src_loc)/rpl/before_next.h',
|
'<(src_loc)/rpl/before_next.h',
|
||||||
|
@ -121,6 +122,7 @@
|
||||||
'<(src_loc)/rpl/range.h',
|
'<(src_loc)/rpl/range.h',
|
||||||
'<(src_loc)/rpl/rpl.h',
|
'<(src_loc)/rpl/rpl.h',
|
||||||
'<(src_loc)/rpl/then.h',
|
'<(src_loc)/rpl/then.h',
|
||||||
|
'<(src_loc)/rpl/type_erased.h',
|
||||||
'<(src_loc)/rpl/variable.h',
|
'<(src_loc)/rpl/variable.h',
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
|
|
Loading…
Reference in New Issue