170 lines
4.1 KiB
C++
170 lines
4.1 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 "lang/lang_tag.h"
|
|
|
|
enum lngtag_count : int;
|
|
|
|
namespace Lang {
|
|
namespace details {
|
|
|
|
inline constexpr auto kPluralCount = 6;
|
|
|
|
template <typename Tag>
|
|
inline constexpr ushort TagValue();
|
|
|
|
template <typename P>
|
|
using S = std::decay_t<decltype(std::declval<P>()(QString()))>;
|
|
|
|
QString Current(ushort key);
|
|
rpl::producer<QString> Viewer(ushort key);
|
|
|
|
template <int Index, typename Type, typename Tuple>
|
|
Type ReplaceUnwrapTuple(Type accumulated, const Tuple &tuple) {
|
|
return accumulated;
|
|
}
|
|
|
|
template <int Index, typename Type, typename Tuple, typename Tag, typename ...Tags>
|
|
Type ReplaceUnwrapTuple(
|
|
Type accumulated,
|
|
const Tuple &tuple,
|
|
Tag tag,
|
|
Tags ...tags) {
|
|
return ReplaceUnwrapTuple<Index + 1>(
|
|
ReplaceTag<Type>::Call(
|
|
std::move(accumulated),
|
|
tag,
|
|
std::get<Index>(tuple)),
|
|
tuple,
|
|
tags...);
|
|
}
|
|
|
|
template <typename ...Tags>
|
|
struct ReplaceUnwrap;
|
|
|
|
template <>
|
|
struct ReplaceUnwrap<> {
|
|
template <typename Type>
|
|
static Type Call(Type accumulated) {
|
|
return accumulated;
|
|
}
|
|
};
|
|
|
|
template <typename Tag, typename ...Tags>
|
|
struct ReplaceUnwrap<Tag, Tags...> {
|
|
template <typename Type, typename Value, typename ...Values>
|
|
static Type Call(
|
|
Type accumulated,
|
|
const Value &value,
|
|
const Values &...values) {
|
|
return ReplaceUnwrap<Tags...>::template Call(
|
|
ReplaceTag<Type>::Call(
|
|
std::move(accumulated),
|
|
TagValue<Tag>(),
|
|
value),
|
|
values...);
|
|
}
|
|
};
|
|
|
|
template <typename ...Tags>
|
|
struct Producer {
|
|
template <typename P, typename ...Values>
|
|
static rpl::producer<S<P>> Combine(ushort base, P p, Values &...values) {
|
|
return rpl::combine(
|
|
Viewer(base),
|
|
std::move(values)...
|
|
) | rpl::map([p = std::move(p)](auto tuple) {
|
|
return ReplaceUnwrapTuple<1>(p(std::get<0>(tuple)), tuple, TagValue<Tags>()...);
|
|
});
|
|
}
|
|
|
|
template <typename P, typename ...Values>
|
|
static S<P> Current(ushort base, P p, const Values &...values) {
|
|
return ReplaceUnwrap<Tags...>::template Call(
|
|
p(Lang::details::Current(base)),
|
|
values...);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct Producer<> {
|
|
template <typename P>
|
|
static rpl::producer<S<P>> Combine(ushort base, P p) {
|
|
return Viewer(base) | rpl::map(std::move(p));
|
|
}
|
|
|
|
template <typename P>
|
|
static S<P> Current(ushort base, P p) {
|
|
return p(Lang::details::Current(base));
|
|
}
|
|
};
|
|
|
|
template <typename ...Tags>
|
|
struct Producer<lngtag_count, Tags...> {
|
|
template <typename P, typename ...Values>
|
|
static rpl::producer<S<P>> Combine(
|
|
ushort base,
|
|
P p,
|
|
lngtag_count type,
|
|
rpl::producer<float64> &count,
|
|
Values &...values) {
|
|
return rpl::combine(
|
|
Viewer(base),
|
|
Viewer(base + 1),
|
|
Viewer(base + 2),
|
|
Viewer(base + 3),
|
|
Viewer(base + 4),
|
|
Viewer(base + 5),
|
|
std::move(count),
|
|
std::move(values)...
|
|
) | rpl::map([base, type, p = std::move(p)](auto tuple) {
|
|
auto plural = Plural(base, std::get<6>(tuple), type);
|
|
const auto select = [&] {
|
|
switch (plural.keyShift) {
|
|
case 0: return std::get<0>(tuple);
|
|
case 1: return std::get<1>(tuple);
|
|
case 2: return std::get<2>(tuple);
|
|
case 3: return std::get<3>(tuple);
|
|
case 4: return std::get<4>(tuple);
|
|
case 5: return std::get<5>(tuple);
|
|
}
|
|
Unexpected("Lang shift value in Plural result.");
|
|
};
|
|
return ReplaceUnwrapTuple<7>(
|
|
ReplaceTag<S<P>>::Call(
|
|
p(select()),
|
|
TagValue<lngtag_count>(),
|
|
StartReplacements<S<P>>::Call(
|
|
std::move(plural.replacement))),
|
|
tuple,
|
|
TagValue<Tags>()...);
|
|
});
|
|
}
|
|
|
|
template <typename P, typename ...Values>
|
|
static S<P> Current(
|
|
ushort base,
|
|
P p,
|
|
lngtag_count type,
|
|
float64 count,
|
|
const Values &...values) {
|
|
auto plural = Plural(base, count, type);
|
|
return ReplaceUnwrap<Tags...>::template Call(
|
|
ReplaceTag<S<P>>::Call(
|
|
p(Lang::details::Current(base + plural.keyShift)),
|
|
TagValue<lngtag_count>(),
|
|
StartReplacements<S<P>>::Call(
|
|
std::move(plural.replacement))),
|
|
values...);
|
|
}
|
|
};
|
|
|
|
} // namespace details
|
|
} // namespace Lang
|