Skip to content

Commit b1f4d2e

Browse files
committed
feat userver: use concepts to work with formats and StrongTypedef
Has no noticeable impact on compile times. Before the change: ``` [1258 ms] [CC]: userver/universal/src/utils/strong_typedef_serialization_test.cpp [started: 1775811100181, finished: 1775811101439] [1282 ms] [CC]: userver/universal/src/utils/strong_typedef_serialization_test.cpp [started: 0 (1775811111417), finished: 1282 (1775811112699)] [2414 ms] [CC]: userver/universal/src/formats/json/value_test.cpp [started: 1775810503597, finished: 1775810506011] [1319 ms] [CC]: userver/universal/src/formats/json/value_builder_test.cpp [started: 1775810503591, finished: 1775810504910] ``` After: ``` [1253 ms] [CC]: userver/universal/src/utils/strong_typedef_serialization_test.cpp [started: 0 (1775811253816), finished: 1253 (1775811255069)] [1253 ms] [CC]: userver/universal/src/utils/strong_typedef_serialization_test.cpp [started: 1775811227027, finished: 1775811228280] [2400 ms] [CC]: userver/universal/src/formats/json/value_test.cpp [started: 1775810366280, finished: 1775810368680] [1319 ms] [CC]: userver/universal/src/formats/json/value_builder_test.cpp [started: 1775810366279, finished: 1775810367598] ``` Tests: протестировано CI commit_hash:9f49f6f04299baa030bb7d09f8e959f8f5c00be7
1 parent b9a8625 commit b1f4d2e

File tree

23 files changed

+223
-273
lines changed

23 files changed

+223
-273
lines changed

chaotic/integration_tests/tests/render/yaml_config.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
USERVER_NAMESPACE_BEGIN
1010

1111
TEST(YamlConfig, Presence) {
12-
static_assert(formats::common::impl::kHasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomStruct1>);
12+
static_assert(formats::common::impl::HasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomStruct1>);
1313

1414
// JSON extra is convertible
15-
static_assert(formats::common::impl::kHasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf__P0>);
15+
static_assert(formats::common::impl::HasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf__P0>);
1616

1717
// Transitively
18-
static_assert(formats::common::impl::kHasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf>);
18+
static_assert(formats::common::impl::HasParse<USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf>);
1919
}
2020

2121
TEST(YamlConfig, Parse) {

core/include/userver/components/container.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ struct DependencyLocator {
8686
///
8787
/// @snippet core/src/dynamic_config/storage/component.cpp LocateDependency example
8888
template <typename T>
89-
std::enable_if_t<formats::common::impl::kHasParse<yaml_config::YamlConfig, T> && std::is_class_v<T>, T>
90-
LocateDependency(WithType<T>, const ComponentConfig& config, const ComponentContext&)
89+
requires(formats::common::impl::HasParse<yaml_config::YamlConfig, T> && std::is_class_v<T>)
90+
T LocateDependency(WithType<T>, const ComponentConfig& config, const ComponentContext&)
9191
{
9292
return config.As<T>();
9393
}

libraries/proto-structs/include/userver/proto-structs/io/userver/utils/strong_typedef_conv.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@ USERVER_NAMESPACE_BEGIN
1111

1212
namespace proto_structs::io {
1313

14-
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TEnable, typename TMessageField>
15-
utils::StrongTypedef<TTag, TStructField, Ops, TEnable> ReadProtoField(
14+
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TMessageField>
15+
utils::StrongTypedef<TTag, TStructField, Ops> ReadProtoField(
1616
ReadContext& ctx,
17-
To<utils::StrongTypedef<TTag, TStructField, Ops, TEnable>>,
17+
To<utils::StrongTypedef<TTag, TStructField, Ops>>,
1818
int field_number,
1919
const TMessageField& message_field
2020
) {
21-
using Type = utils::StrongTypedef<TTag, TStructField, Ops, TEnable>;
21+
using Type = utils::StrongTypedef<TTag, TStructField, Ops>;
2222
return Type{ctx.ReadField<TStructField>(field_number, message_field)};
2323
}
2424

25-
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TEnable, typename TMessageField>
25+
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TMessageField>
2626
void WriteProtoField(
2727
WriteContext& ctx,
28-
const utils::StrongTypedef<TTag, TStructField, Ops, TEnable>& struct_field,
28+
const utils::StrongTypedef<TTag, TStructField, Ops>& struct_field,
2929
int field_number,
3030
TMessageField& message_field
3131
) {
3232
ctx.WriteField(struct_field.GetUnderlying(), field_number, message_field);
3333
}
3434

35-
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TEnable, typename TMessageField>
35+
template <typename TTag, typename TStructField, utils::StrongTypedefOps Ops, typename TMessageField>
3636
void WriteProtoField(
3737
WriteContext& ctx,
38-
utils::StrongTypedef<TTag, TStructField, Ops, TEnable>&& struct_field,
38+
utils::StrongTypedef<TTag, TStructField, Ops>&& struct_field,
3939
int field_number,
4040
TMessageField& message_field
4141
) {

mongo/include/userver/formats/bson/value.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class Value {
171171
template <typename T>
172172
auto As() const {
173173
static_assert(
174-
formats::common::impl::kHasParse<Value, T>,
174+
formats::common::impl::HasParse<Value, T>,
175175
"There is no `Parse(const Value&, formats::parse::To<T>)` in namespace "
176176
"of `T` or `formats::parse`. "
177177
"Probably you have not provided a `Parse` function overload."
@@ -204,16 +204,15 @@ class Value {
204204
/// For example, `true` may be converted to 1.0.
205205
template <typename T>
206206
T ConvertTo() const {
207-
if constexpr (formats::common::impl::kHasConvert<Value, T>) {
207+
if constexpr (formats::common::impl::HasConvert<Value, T>) {
208208
return Convert(*this, formats::parse::To<T>{});
209-
} else if constexpr (formats::common::impl::kHasParse<Value, T>) {
209+
} else if constexpr (formats::common::impl::HasParse<Value, T>) {
210210
return Parse(*this, formats::parse::To<T>{});
211211
} else {
212212
static_assert(
213213
!sizeof(T),
214-
"There is no `Convert(const Value&, formats::parse::To<T>)` or"
215-
"`Parse(const Value&, formats::parse::To<T>)`"
216-
"in namespace of `T` or `formats::parse`. "
214+
"There is no `Convert(const Value&, formats::parse::To<T>)` or "
215+
"`Parse(const Value&, formats::parse::To<T>)` in namespace of `T` or `formats::parse`. "
217216
"Probably you have not provided a `Convert` function overload."
218217
);
219218
}

mongo/include/userver/formats/bson/value_builder.hpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ USERVER_NAMESPACE_BEGIN
2222

2323
namespace formats::bson {
2424

25-
// clang-format off
26-
2725
/// @brief Builder for BSON.
2826
///
2927
/// Class provides methods for building BSON. For read only access to the
@@ -38,9 +36,6 @@ namespace formats::bson {
3836
/// @snippet formats/bson/value_builder_test.cpp Sample Customization formats::bson::ValueBuilder usage
3937
///
4038
/// @see @ref scripts/docs/en/userver/formats.md
41-
42-
// clang-format on
43-
4439
class ValueBuilder {
4540
public:
4641
using iterator = Iterator<ValueBuilder>;
@@ -119,11 +114,11 @@ class ValueBuilder {
119114

120115
/// @brief Access member by key for modification.
121116
/// @throw `TypeMismatchException` if not object or null value.
122-
template <
123-
typename Tag,
124-
utils::StrongTypedefOps Ops,
125-
typename Enable = std::enable_if_t<utils::IsStrongTypedefLoggable(Ops)>>
126-
ValueBuilder operator[](const utils::StrongTypedef<Tag, std::string, Ops>& name);
117+
template <typename Tag, utils::StrongTypedefOps Ops>
118+
requires(utils::IsStrongTypedefLoggable(Ops))
119+
ValueBuilder operator[](const utils::StrongTypedef<Tag, std::string, Ops>& name) {
120+
return (*this)[name.GetUnderlying()];
121+
}
127122

128123
/// @brief Retrieves array element by index
129124
/// @throws TypeMismatchException if value is not an array or `null`
@@ -208,20 +203,14 @@ class ValueBuilder {
208203
impl::ValueImplPtr impl_;
209204
};
210205

211-
template <typename Tag, utils::StrongTypedefOps Ops, typename Enable>
212-
ValueBuilder ValueBuilder::operator[](const utils::StrongTypedef<Tag, std::string, Ops>& name) {
213-
return (*this)[name.GetUnderlying()];
214-
}
215-
216206
template <typename T>
217207
Value ValueBuilder::DoSerialize(const T& t) {
218208
static_assert(
219-
formats::common::impl::kHasSerialize<Value, T>,
209+
formats::common::impl::HasSerialize<Value, T>,
220210
"There is no `Serialize(const T&, formats::serialize::To<bson::Value>)` "
221211
"in namespace of `T` or `formats::serialize`. "
222212
""
223-
"Probably you forgot to include the "
224-
"<userver/formats/serialize/common_containers.hpp> or you "
213+
"Probably you forgot to include the <userver/formats/serialize/common_containers.hpp> or you "
225214
"have not provided a `Serialize` function overload."
226215
);
227216

postgresql/include/userver/storages/postgres/io/row_types.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ constexpr bool DetectIsSuitableRowType() {
107107
template <typename T>
108108
struct IsSuitableRowType : BoolConstant<detail::DetectIsSuitableRowType<T>()> {};
109109

110-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
111-
struct IsSuitableRowType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> : IsSuitableRowType<T> {};
110+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
111+
struct IsSuitableRowType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> : IsSuitableRowType<T> {};
112112

113113
template <typename T>
114114
inline constexpr bool kIsSuitableRowType = IsSuitableRowType<T>::value;
@@ -131,8 +131,8 @@ struct RowCategory
131131
RowCategoryConstant<RowCategoryType::kAggregate>,
132132
RowCategoryConstant<RowCategoryType::kNonRow>>>> {};
133133

134-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
135-
struct RowCategory<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> : RowCategory<T> {};
134+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
135+
struct RowCategory<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> : RowCategory<T> {};
136136

137137
template <typename T>
138138
inline constexpr RowCategoryType kRowCategory = RowCategory<T>::value;

postgresql/include/userver/storages/postgres/io/strong_typedef.hpp

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,33 @@ namespace traits {
4141

4242
// Helper to detect if the strong typedef mapping is explicitly defined,
4343
// e.g. TimePointTz
44-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
44+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
4545
inline constexpr bool kIsStrongTypedefDirectlyMapped =
4646
// NOLINTNEXTLINE(google-readability-casting)
47-
kIsMappedToUserType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> ||
47+
kIsMappedToUserType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> ||
4848
// NOLINTNEXTLINE(google-readability-casting)
49-
kIsMappedToSystemType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> ||
49+
kIsMappedToSystemType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> ||
5050
// NOLINTNEXTLINE(google-readability-casting)
51-
kIsMappedToArray<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>;
51+
kIsMappedToArray<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>;
5252

53-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
54-
struct IsMappedToPg<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
53+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
54+
struct IsMappedToPg<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>
5555
// NOLINTNEXTLINE(google-readability-casting)
56-
: BoolConstant<kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> || kIsMappedToPg<T>> {};
56+
: BoolConstant<kIsStrongTypedefDirectlyMapped<Tag, T, Ops> || kIsMappedToPg<T>> {};
5757

5858
// Mark that strong typedef mapping is a special case for disambiguating
5959
// specialization of CppToPg
60-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
61-
struct IsSpecialMapping<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
60+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
61+
struct IsSpecialMapping<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>
6262
// NOLINTNEXTLINE(google-readability-casting)
63-
: BoolConstant<!kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> && kIsMappedToPg<T>> {};
63+
: BoolConstant<!kIsStrongTypedefDirectlyMapped<Tag, T, Ops> && kIsMappedToPg<T>> {};
6464

65-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
66-
struct IsNullable<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> : IsNullable<T> {};
65+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
66+
struct IsNullable<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> : IsNullable<T> {};
6767

68-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
69-
struct GetSetNull<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> {
70-
using ValueType = USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>;
68+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
69+
struct GetSetNull<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> {
70+
using ValueType = USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>;
7171
using UnderlyingGetSet = GetSetNull<T>;
7272
inline static bool IsNull(const ValueType& v) { return UnderlyingGetSet::IsNull(v.GetUnderlying()); }
7373
inline static void SetNull(ValueType& v) { UnderlyingGetSet::SetNull(v.GetUnderlying()); }
@@ -108,10 +108,10 @@ using EnableIfCanUseEnumAsStrongTypedef = std::enable_if_t<impl::CheckCanUseEnum
108108

109109
} // namespace traits
110110

111-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
112-
struct BufferFormatter<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
113-
: detail::BufferFormatterBase<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> {
114-
using BaseType = detail::BufferFormatterBase<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>;
111+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
112+
struct BufferFormatter<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>
113+
: detail::BufferFormatterBase<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>> {
114+
using BaseType = detail::BufferFormatterBase<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>;
115115
using BaseType::BaseType;
116116

117117
template <typename Buffer>
@@ -149,28 +149,27 @@ struct StrongTypedefParser<StrongTypedef, true> : BufferParserBase<StrongTypedef
149149

150150
} // namespace detail
151151

152-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
153-
struct BufferParser<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
152+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
153+
struct BufferParser<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>
154154
: detail::StrongTypedefParser<
155-
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>,
155+
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>,
156156
detail::kParserRequiresTypeCategories<T>> {
157157
using BaseType = detail::StrongTypedefParser<
158-
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>,
158+
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>,
159159
detail::kParserRequiresTypeCategories<T>>;
160160
using BaseType::BaseType;
161161
};
162162

163163
// StrongTypedef template mapping specialization
164-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
164+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
165165
struct CppToPg<
166-
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>,
167-
std::enable_if_t<!traits::kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> && traits::kIsMappedToPg<T>>>
168-
: CppToPg<T> {};
166+
USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>,
167+
std::enable_if_t<!traits::kIsStrongTypedefDirectlyMapped<Tag, T, Ops> && traits::kIsMappedToPg<T>>> : CppToPg<T> {};
169168

170169
namespace traits {
171170

172-
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops, typename Enable>
173-
struct ParserBufferCategory<BufferParser<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>>
171+
template <typename Tag, typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops>
172+
struct ParserBufferCategory<BufferParser<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops>>>
174173
: ParserBufferCategory<typename traits::IO<T>::ParserType> {};
175174

176175
} // namespace traits

universal/include/userver/formats/common/meta.hpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,21 @@ namespace impl {
2121
/// `formats` doesn't support SFINAE, so e.g. `kHasParse` can return `true`
2222
/// while a usage of `Parse` will fail to compile.
2323

24-
template <typename Value, typename T>
25-
using HasParse = decltype(Parse(std::declval<const Value&>(), parse::To<T>{}));
26-
27-
template <typename Value, typename T>
28-
using HasSerialize = decltype(Serialize(std::declval<const T&>(), serialize::To<Value>{}));
29-
30-
template <typename Value, typename T>
31-
using HasConvert = decltype(Convert(std::declval<const Value&>(), parse::To<T>{}));
32-
33-
template <typename Value>
34-
using IsFormatValue = typename Value::ParseException;
35-
3624
template <class Value, class T>
37-
constexpr inline bool kHasParse = meta::IsDetected<HasParse, Value, T>;
25+
concept HasParse = requires(const Value& value) { Parse(value, parse::To<T>{}); };
3826

3927
template <class Value, class T>
40-
constexpr inline bool kHasSerialize = meta::IsDetected<HasSerialize, Value, T>;
28+
concept HasSerialize = requires(const T& x) { Serialize(x, serialize::To<Value>{}); };
4129

4230
template <class Value, class T>
43-
constexpr inline bool kHasConvert = meta::IsDetected<HasConvert, Value, T>;
31+
concept HasConvert = requires(const Value& value) { Convert(value, parse::To<T>{}); };
4432

4533
} // namespace impl
4634

4735
/// Used in `Parse` overloads that are templated on `Value`, avoids clashing
4836
/// with `Parse` from string
4937
template <class Value>
50-
constexpr inline bool kIsFormatValue = meta::IsDetected<impl::IsFormatValue, Value>;
38+
concept kIsFormatValue = requires { typename Value::ParseException; }; // NOLINT(readability-identifier-naming)
5139

5240
// Unwraps a transient type - tag types, for which ADL-found `Parse` returns
5341
// another type, not the type specified in `formats::parse::To`. For example,

universal/include/userver/formats/common/utils.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ ValueBuilder GetAtPath(ValueBuilder& parent, std::vector<std::string>&& path, st
4444
/// @note For empty `path` this function returns `parent`.
4545
/// @throws TypeMismatchException if there is a non-object node in the middle of
4646
/// `path`
47-
template <typename Value>
48-
std::enable_if_t<common::kIsFormatValue<Value>, Value> GetAtPath(Value parent, const std::vector<std::string>& path) {
47+
template <common::kIsFormatValue Value>
48+
Value GetAtPath(Value parent, const std::vector<std::string>& path) {
4949
auto current_value = std::move(parent);
5050
for (const auto& current_key : path) {
5151
current_value = current_value[current_key];
@@ -58,10 +58,8 @@ std::enable_if_t<common::kIsFormatValue<Value>, Value> GetAtPath(Value parent, c
5858
/// @throws TypeMismatchException if there is a non-object node in the middle of
5959
/// `path`
6060
template <typename ValueBuilder>
61-
std::enable_if_t<!common::kIsFormatValue<ValueBuilder>, ValueBuilder> GetAtPath(
62-
ValueBuilder& parent,
63-
std::vector<std::string>&& path
64-
) {
61+
requires(!common::kIsFormatValue<ValueBuilder>)
62+
ValueBuilder GetAtPath(ValueBuilder& parent, std::vector<std::string>&& path) {
6563
return impl::GetAtPath(parent, std::move(path), path.size());
6664
}
6765

universal/include/userver/formats/json/value.hpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,9 @@ class Value {
352352
template <typename T>
353353
auto Value::As() const {
354354
static_assert(
355-
formats::common::impl::kHasParse<Value, T>,
356-
"There is no `Parse(const Value&, formats::parse::To<T>)` "
357-
"in namespace of `T` or `formats::parse`. "
358-
"Probably you forgot to include the "
359-
"<userver/formats/parse/common_containers.hpp> or you "
355+
formats::common::impl::HasParse<Value, T>,
356+
"There is no `Parse(const Value&, formats::parse::To<T>)` in namespace of `T` or `formats::parse`. "
357+
"Probably you forgot to include the <userver/formats/parse/common_containers.hpp> or you "
360358
"have not provided a `Parse` function overload."
361359
);
362360

@@ -405,17 +403,15 @@ auto Value::As(Value::DefaultConstructed) const {
405403

406404
template <typename T>
407405
T Value::ConvertTo() const {
408-
if constexpr (formats::common::impl::kHasConvert<Value, T>) {
406+
if constexpr (formats::common::impl::HasConvert<Value, T>) {
409407
return Convert(*this, formats::parse::To<T>{});
410-
} else if constexpr (formats::common::impl::kHasParse<Value, T>) {
408+
} else if constexpr (formats::common::impl::HasParse<Value, T>) {
411409
return Parse(*this, formats::parse::To<T>{});
412410
} else {
413411
static_assert(
414412
!sizeof(T),
415-
"There is no `Convert(const Value&, formats::parse::To<T>)` or"
416-
"`Parse(const Value&, formats::parse::To<T>)`"
417-
"in namespace of `T` or `formats::parse`. "
418-
"Probably you have not provided a `Convert` function overload."
413+
"There is no `Convert(const Value&, formats::parse::To<T>)` or `Parse(const Value&, formats::parse::To<T>)`"
414+
"in namespace of `T` or `formats::parse`. Probably you have not provided a `Convert` function overload."
419415
);
420416
}
421417
}

0 commit comments

Comments
 (0)