in src/common/serde/Serde.h [465:680]
inline Result<Void> deserialize(auto &o, auto &&in) requires is_specialization<std::decay_t<decltype(in)>, In> {
using T = std::decay_t<decltype(o)>;
using I = std::decay_t<decltype(in)>;
constexpr bool isBinaryIn = requires { typename I::is_binary_in; };
if constexpr (!isBinaryIn && requires { function_first_parameter_t<&T::serdeFromReadable>{}; }) {
// 0. custom serde impl.
function_first_parameter_t<&T::serdeFromReadable> from{};
RETURN_AND_LOG_ON_ERROR(deserialize(from, in));
auto result = T::serdeFromReadable(from);
RETURN_AND_LOG_ON_ERROR(result);
o = std::move(*result);
return Void{};
} else if constexpr (!isBinaryIn && requires { function_first_parameter_t<&SerdeMethod<T>::serdeFromReadable>{}; }) {
function_first_parameter_t<&SerdeMethod<T>::serdeFromReadable> from{};
RETURN_AND_LOG_ON_ERROR(deserialize(from, in));
auto result = SerdeMethod<T>::serdeFromReadable(from);
RETURN_AND_LOG_ON_ERROR(result);
o = std::move(*result);
return Void{};
} else if constexpr (requires { function_first_parameter_t<&SerdeMethod<T>::serdeFrom>{}; }) {
// 0. custom serde impl.
function_first_parameter_t<&SerdeMethod<T>::serdeFrom> from{};
RETURN_AND_LOG_ON_ERROR(deserialize(from, in));
auto result = SerdeMethod<T>::serdeFrom(from);
RETURN_AND_LOG_ON_ERROR(result);
o = std::move(*result);
return Void{};
} else if constexpr (!isBinaryIn && requires { SerdeMethod<T>::deserializeReadable(o, in); }) {
return SerdeMethod<T>::deserializeReadable(o, in);
} else if constexpr (requires { SerdeMethod<T>::deserialize(o, in); }) {
return SerdeMethod<T>::deserialize(o, in);
} else if constexpr (SerdeType<T>) {
auto table = in.parseTable();
RETURN_AND_LOG_ON_ERROR(table);
if constexpr (isBinaryIn) {
return refl::Helper::iterate<T>(
[&](auto type) -> Result<Void> {
if (LIKELY(*table)) {
return deserialize(o.*type.getter, *table);
}
// Missing fields at the end are acceptable.
return Void{};
},
[&]() -> Result<Void> {
table = in.parseTable();
RETURN_AND_LOG_ON_ERROR(table);
return Void{};
});
} else {
return refl::Helper::iterate<T>([&](auto type) -> Result<Void> {
auto value = table->parseKey(type.name);
if (LIKELY(bool(value))) {
return deserialize(o.*type.getter, *value);
} else {
using ItemType = std::decay_t<decltype(o.*type.getter)>;
if constexpr (is_optional_v<ItemType>) {
o.*type.getter = std::nullopt;
} else if constexpr (is_unique_ptr_v<ItemType> || is_shared_ptr_v<ItemType>) {
o.*type.getter = nullptr;
}
}
return Void{};
});
}
} else if constexpr (std::is_same_v<std::string, T> || std::is_same_v<std::string_view, T>) {
auto result = in.parseString();
RETURN_AND_LOG_ON_ERROR(result);
o = *result;
return Void{};
} else if constexpr (is_optional_v<T>) {
Optional optional;
RETURN_AND_LOG_ON_ERROR(in.parseOptional(optional));
if (optional == Optional::HasValue) {
std::remove_cv_t<typename T::value_type> value;
RETURN_AND_LOG_ON_ERROR(deserialize(value, in));
o = std::move(value);
} else {
o = std::nullopt;
}
return Void{};
} else if constexpr (is_unique_ptr_v<T> || is_shared_ptr_v<T>) {
Optional optional;
RETURN_AND_LOG_ON_ERROR(in.parseOptional(optional));
if (optional == Optional::HasValue) {
if constexpr (is_unique_ptr_v<T>) {
o = std::make_unique<typename T::element_type>();
} else {
o = std::make_shared<typename T::element_type>();
}
RETURN_AND_LOG_ON_ERROR(deserialize(*o, in));
} else {
o = nullptr;
}
return Void{};
} else if constexpr (is_variant_v<T>) {
auto variant = in.parseVariant();
RETURN_AND_LOG_ON_ERROR(variant);
return callByIdx<type_list_t<T>>(
[&](auto type) -> Result<Void> {
if constexpr (std::is_same_v<decltype(type), std::nullptr_t>) {
if constexpr (is_auto_fallback_variant_v<T>) {
UnknownVariantType uvt;
uvt.type = variant->first;
o = std::move(uvt);
return Void{};
} else {
return makeError(StatusCode::kSerdeVariantIndexExceeded);
}
} else {
RETURN_AND_LOG_ON_ERROR(deserialize(type, variant->second));
o = std::move(type);
return Void{};
}
},
variantTypeNameToIndex<T>(variant->first));
return Void{};
} else if constexpr (is_generic_pair_v<T> && isBinaryIn) {
RETURN_AND_LOG_ON_ERROR(deserialize(o.first, in));
RETURN_AND_LOG_ON_ERROR(deserialize(o.second, in));
return Void{};
} else if constexpr (Container<T> && isBinaryIn) {
Varint64 size = 0;
RETURN_AND_LOG_ON_ERROR(deserialize(size, in));
o.clear();
if constexpr (requires { o.reserve(size); }) {
o.reserve(size);
}
auto inserter = std::inserter(o, o.end());
for (uint32_t i = 0; i < size; ++i) {
if constexpr (is_generic_pair_v<typename T::value_type>) {
std::remove_cv_t<typename T::value_type::first_type> first;
RETURN_AND_LOG_ON_ERROR(deserialize(first, in));
std::remove_cv_t<typename T::value_type::second_type> second;
RETURN_AND_LOG_ON_ERROR(deserialize(second, in));
inserter++ = typename T::value_type{std::move(first), std::move(second)};
} else {
auto value = DefaultConstructor<std::remove_cv_t<typename T::value_type>>::construct();
RETURN_AND_LOG_ON_ERROR(deserialize(value, in));
inserter++ = std::move(value);
}
}
return Void{};
} else if constexpr (is_vector_v<T> || is_set_v<T> || is_map_v<T>) {
auto containerResult = in.parseContainer();
RETURN_AND_LOG_ON_ERROR(containerResult);
auto size = containerResult->first;
auto it = std::move(containerResult->second);
o.clear();
if constexpr (requires { o.reserve(size); }) {
o.reserve(size);
}
auto inserter = std::inserter(o, o.end());
for (uint32_t i = 0; i < size; ++i) {
if constexpr (is_map_v<T>) {
auto keyResult = in.fetchKey(it);
RETURN_AND_LOG_ON_ERROR(keyResult);
std::string_view key = *keyResult;
using KeyType = std::remove_cv_t<typename T::value_type::first_type>;
KeyType first;
if constexpr (requires { first = KeyType{key}; }) {
first = KeyType{key};
} else if constexpr (requires { scn::scan(key, "{}", first); }) {
auto result = scn::scan(key, "{}", first);
if (!result) {
return makeError(StatusCode::kInvalidArg);
}
} else if constexpr (requires { scn::scan(key, "{}", first.toUnderType()); }) {
auto result = scn::scan(key, "{}", first.toUnderType());
if (!result) {
return makeError(StatusCode::kInvalidArg);
}
} else {
return makeError(StatusCode::kInvalidArg);
}
std::remove_cv_t<typename T::value_type::second_type> second;
RETURN_AND_LOG_ON_ERROR(deserialize(second, in.fetchValue(it)));
inserter++ = typename T::value_type{std::move(first), std::move(second)};
in.next(it);
} else {
std::remove_cv_t<typename T::value_type> value;
RETURN_AND_LOG_ON_ERROR(deserialize(value, in.fetchAndNext(it)));
inserter++ = std::move(value);
}
}
return Void{};
} else if constexpr (isBinaryIn && SerdeCopyable<T>) {
return in.parseCopyable(o);
} else if constexpr (std::is_same_v<T, bool>) {
auto result = in.parseBoolean();
RETURN_AND_LOG_ON_ERROR(result);
o = *result;
return Void{};
} else if constexpr (std::is_integral_v<T>) {
auto result = in.parseInteger();
RETURN_AND_LOG_ON_ERROR(result);
o = *result;
return Void{};
} else if constexpr (std::is_floating_point_v<T>) {
auto result = in.parseFloat();
RETURN_AND_LOG_ON_ERROR(result);
o = *result;
return Void{};
} else if constexpr (std::is_enum_v<T>) {
std::string_view str;
RETURN_AND_LOG_ON_ERROR(deserialize(str, in));
auto result = magic_enum::enum_cast<T>(str);
if (result.has_value()) {
o = *result;
return Void{};
}
return makeError(StatusCode::kSerdeUnknownEnumValue,
fmt::format("unknown enum value {} for type {}", str, nameof::nameof_full_type<T>()));
} else {
return notSupportToDeserialize(o, in);
}
}