212 lines
5.0 KiB
C++
212 lines
5.0 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#pragma once
|
|
|
|
#include <rpl/producer.h>
|
|
|
|
namespace rpl {
|
|
namespace details {
|
|
|
|
template <
|
|
typename Transform,
|
|
typename NewValue,
|
|
typename Error,
|
|
typename Handlers>
|
|
class map_transform_helper {
|
|
public:
|
|
map_transform_helper(
|
|
Transform &&transform,
|
|
const consumer<NewValue, Error, Handlers> &consumer)
|
|
: _consumer(consumer)
|
|
, _transform(std::move(transform)) {
|
|
}
|
|
template <
|
|
typename OtherValue,
|
|
typename = std::enable_if_t<
|
|
std::is_rvalue_reference_v<OtherValue&&>>>
|
|
void operator()(OtherValue &&value) const {
|
|
_consumer.put_next_forward(
|
|
details::callable_invoke(_transform, std::move(value)));
|
|
}
|
|
template <
|
|
typename OtherValue,
|
|
typename = decltype(
|
|
std::declval<Transform>()(const_ref_val<OtherValue>()))>
|
|
void operator()(const OtherValue &value) const {
|
|
_consumer.put_next_forward(
|
|
details::callable_invoke(_transform, value));
|
|
}
|
|
|
|
private:
|
|
consumer<NewValue, Error, Handlers> _consumer;
|
|
Transform _transform;
|
|
|
|
};
|
|
|
|
template <
|
|
typename Transform,
|
|
typename NewValue,
|
|
typename Error,
|
|
typename Handlers,
|
|
typename = std::enable_if_t<
|
|
std::is_rvalue_reference_v<Transform&&>>>
|
|
inline map_transform_helper<Transform, NewValue, Error, Handlers>
|
|
map_transform(
|
|
Transform &&transform,
|
|
const consumer<NewValue, Error, Handlers> &consumer) {
|
|
return { std::move(transform), consumer };
|
|
}
|
|
|
|
template <typename Transform>
|
|
class map_helper {
|
|
public:
|
|
template <typename OtherTransform>
|
|
map_helper(OtherTransform &&transform)
|
|
: _transform(std::forward<OtherTransform>(transform)) {
|
|
}
|
|
|
|
template <
|
|
typename Value,
|
|
typename Error,
|
|
typename Generator,
|
|
typename NewValue = details::callable_result<
|
|
Transform,
|
|
Value>>
|
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
|
return make_producer<NewValue, Error>([
|
|
initial = std::move(initial),
|
|
transform = std::move(_transform)
|
|
](const auto &consumer) mutable {
|
|
return std::move(initial).start(
|
|
map_transform(
|
|
std::move(transform),
|
|
consumer
|
|
), [consumer](auto &&error) {
|
|
consumer.put_error_forward(
|
|
std::forward<decltype(error)>(error));
|
|
}, [consumer] {
|
|
consumer.put_done();
|
|
});
|
|
});
|
|
}
|
|
|
|
private:
|
|
Transform _transform;
|
|
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
template <typename Transform>
|
|
inline auto map(Transform &&transform)
|
|
-> details::map_helper<std::decay_t<Transform>> {
|
|
return details::map_helper<std::decay_t<Transform>>(
|
|
std::forward<Transform>(transform));
|
|
}
|
|
|
|
namespace details {
|
|
|
|
template <
|
|
typename Transform,
|
|
typename Value,
|
|
typename NewError,
|
|
typename Handlers>
|
|
class map_error_transform_helper {
|
|
public:
|
|
map_error_transform_helper(
|
|
Transform &&transform,
|
|
const consumer<Value, NewError, Handlers> &consumer)
|
|
: _transform(std::move(transform))
|
|
, _consumer(consumer) {
|
|
}
|
|
template <
|
|
typename OtherError,
|
|
typename = std::enable_if_t<
|
|
std::is_rvalue_reference_v<OtherError&&>>>
|
|
void operator()(OtherError &&error) const {
|
|
_consumer.put_error_forward(
|
|
details::callable_invoke(_transform, std::move(error)));
|
|
}
|
|
template <
|
|
typename OtherError,
|
|
typename = decltype(
|
|
std::declval<Transform>()(const_ref_val<OtherError>()))>
|
|
void operator()(const OtherError &error) const {
|
|
_consumer.put_error_forward(
|
|
details::callable_invoke(_transform, error));
|
|
}
|
|
|
|
private:
|
|
consumer<Value, NewError, Handlers> _consumer;
|
|
Transform _transform;
|
|
|
|
};
|
|
|
|
template <
|
|
typename Transform,
|
|
typename Value,
|
|
typename NewError,
|
|
typename Handlers,
|
|
typename = std::enable_if_t<
|
|
std::is_rvalue_reference_v<Transform&&>>>
|
|
inline map_error_transform_helper<Transform, Value, NewError, Handlers>
|
|
map_error_transform(
|
|
Transform &&transform,
|
|
const consumer<Value, NewError, Handlers> &consumer) {
|
|
return { std::move(transform), consumer };
|
|
}
|
|
|
|
template <typename Transform>
|
|
class map_error_helper {
|
|
public:
|
|
template <typename OtherTransform>
|
|
map_error_helper(OtherTransform &&transform)
|
|
: _transform(std::forward<OtherTransform>(transform)) {
|
|
}
|
|
|
|
template <
|
|
typename Value,
|
|
typename Error,
|
|
typename Generator,
|
|
typename NewError = details::callable_result<
|
|
Transform,
|
|
Error>>
|
|
auto operator()(producer<Value, Error, Generator> &&initial) {
|
|
return make_producer<Value, NewError>([
|
|
initial = std::move(initial),
|
|
transform = std::move(_transform)
|
|
](const auto &consumer) mutable {
|
|
return std::move(initial).start(
|
|
[consumer](auto &&value) {
|
|
consumer.put_next_forward(
|
|
std::forward<decltype(value)>(value));
|
|
}, map_error_transform(
|
|
std::move(transform),
|
|
consumer
|
|
), [consumer] {
|
|
consumer.put_done();
|
|
});
|
|
});
|
|
}
|
|
|
|
private:
|
|
Transform _transform;
|
|
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
template <typename Transform>
|
|
inline auto map_error(Transform &&transform)
|
|
-> details::map_error_helper<std::decay_t<Transform>> {
|
|
return details::map_error_helper<std::decay_t<Transform>>(
|
|
std::forward<Transform>(transform));
|
|
}
|
|
|
|
} // namespace rpl
|