|
1 | 1 | #pragma once |
2 | 2 |
|
| 3 | +/// @file userver/chaotic/convert.hpp |
| 4 | +/// @brief @copybrief chaotic::ConvertTo |
| 5 | + |
| 6 | +#include <cstdint> |
| 7 | +#include <string_view> |
3 | 8 | #include <type_traits> |
4 | 9 |
|
5 | 10 | #include <userver/chaotic/convert/to.hpp> |
6 | 11 |
|
7 | 12 | USERVER_NAMESPACE_BEGIN |
8 | 13 |
|
9 | | -namespace chaotic::convert { |
| 14 | +namespace chaotic { |
| 15 | +namespace convert { |
10 | 16 |
|
11 | | -template <typename T, typename U> |
12 | | -constexpr U Convert(const T& value, To<U>) { |
| 17 | +namespace impl { |
| 18 | + |
| 19 | +template <typename YourType> |
| 20 | +constexpr void ReportMissingConvert(std::string_view, chaotic::convert::To<YourType>) { |
| 21 | + static_assert( |
| 22 | + sizeof(YourType) && false, |
| 23 | + "There is no `YourType Convert(std::string_view, chaotic::convert::To<YourType>)` in namespace of `YourType` " |
| 24 | + "or `chaotic::convert`. Probably you have not provided a `Convert` function overload." |
| 25 | + ); |
| 26 | +} |
| 27 | + |
| 28 | +template <typename YourType> |
| 29 | +constexpr void ReportMissingConvert(std::int64_t, chaotic::convert::To<YourType>) { |
| 30 | + static_assert( |
| 31 | + sizeof(YourType) && false, |
| 32 | + "There is no `YourType Convert(std::int64_t, chaotic::convert::To<YourType>)` in namespace of `YourType` or " |
| 33 | + "`chaotic::convert`. Probably you have not provided a `Convert` function overload." |
| 34 | + ); |
| 35 | +} |
| 36 | + |
| 37 | +template <class T, class YourType> |
| 38 | +constexpr void ReportMissingConvert(T&&, chaotic::convert::To<YourType>) { |
13 | 39 | static_assert( |
14 | | - std::is_constructible_v<U, const T&>, |
15 | | - "There is no `Convert(const Value&, chaotic::convert::To<T>)` in " |
16 | | - "namespace of `T` or `chaotic::convert`. Probably you have not provided " |
17 | | - "a `Convert` function overload." |
| 40 | + sizeof(YourType) && false, |
| 41 | + "There is no `YourType Convert(T&&, chaotic::convert::To<YourType>)` in namespace of `T`, `YourType` or " |
| 42 | + "`chaotic::convert`. Probably you have not provided a `Convert` function overload." |
18 | 43 | ); |
| 44 | +} |
| 45 | + |
| 46 | +template <typename YourType, typename T> |
| 47 | +constexpr void ReportMissingConvert(const YourType&, chaotic::convert::To<T>) { |
| 48 | + static_assert( |
| 49 | + sizeof(YourType) && false, |
| 50 | + "There is no `T Convert(const YourType&, chaotic::convert::To<T>)` in namespace of `T`, `YourType` or " |
| 51 | + "`chaotic::convert`. Probably you have not provided a `Convert` function overload." |
| 52 | + ); |
| 53 | +} |
| 54 | + |
| 55 | +template <typename TargetType> |
| 56 | +class ConvertCPO { |
| 57 | +public: |
| 58 | + template <typename... Args> |
| 59 | + constexpr void operator()(Args&&... args) const noexcept { |
| 60 | + static_assert(sizeof...(Args) == 1, "Should be used with a single argument only"); |
| 61 | + impl::ReportMissingConvert(std::forward<Args>(args)..., chaotic::convert::To<TargetType>{}); |
| 62 | + } |
19 | 63 |
|
| 64 | + template <typename T> |
| 65 | + constexpr auto operator()(T&& value |
| 66 | + ) const -> decltype(Convert(std::forward<T>(value), chaotic::convert::To<TargetType>{})) |
| 67 | + { |
| 68 | + return Convert(std::forward<T>(value), chaotic::convert::To<TargetType>{}); |
| 69 | + } |
| 70 | +}; |
| 71 | + |
| 72 | +} // namespace impl |
| 73 | + |
| 74 | +template <typename T, typename U> |
| 75 | +constexpr std::enable_if_t<std::is_constructible_v<U, const T&>, U> Convert(const T& value, To<U>) { |
20 | 76 | return U{value}; |
21 | 77 | } |
22 | 78 |
|
23 | | -} // namespace chaotic::convert |
| 79 | +} // namespace convert |
| 80 | + |
| 81 | +/// @brief Helper function to dispatch to user defined `Convert(X, To<Y>)` functions. |
| 82 | +/// Use like `chaotic::ConvertTo<TargetType>(value_from)`. |
| 83 | +template <typename To> |
| 84 | +constexpr inline convert::impl::ConvertCPO<To> ConvertTo{}; |
| 85 | + |
| 86 | +} // namespace chaotic |
24 | 87 |
|
25 | 88 | USERVER_NAMESPACE_END |
0 commit comments