Add ConstructT option for boost pfr FieldSetHelper With

This commit is contained in:
sha512sum 2024-10-09 18:19:52 +00:00
parent e7e84860cc
commit eafdecba7b
8 changed files with 160 additions and 28 deletions

1
.gitignore vendored
View file

@ -29,3 +29,4 @@ ext/
libxmlplusplus-prefix/ libxmlplusplus-prefix/
spdlog.pc spdlog.pc
build* build*
larra

View file

@ -0,0 +1,74 @@
#pragma once
#include <libxml++/document.h>
#include <optional>
#include <string>
#include <variant>
namespace larra::xmpp::client::sasl {
struct Failure : std::exception {
std::optional<std::string> text;
constexpr Failure(std::optional<std::string> str) : text(std::move(str)) {};
static constexpr auto kDefaultName = "failure";
static constexpr auto kDefaultNamespace = "urn:ietf:params:xml:ns:xmpp-sasl";
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<Failure> {
return std::optional{Failure{[&] -> std::optional<std::string> {
auto textNode = element->get_first_child("text");
if(!textNode) {
return std::nullopt;
}
auto text = dynamic_cast<xmlpp::Element*>(textNode);
if(!text) {
return std::nullopt;
}
auto childText = text->get_first_child_text();
if(!childText) {
return std::nullopt;
}
return childText->get_content();
}()}};
}
static constexpr auto Parse(xmlpp::Element* element) -> Failure {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const Failure& failure) {
}
[[nodiscard]] constexpr auto what() const noexcept -> const char* override {
return this->text ? this->text->c_str() : "Sasl failure";
}
};
struct Success {
static constexpr auto kDefaultName = "success";
static constexpr auto kDefaultNamespace = "urn:ietf:params:xml:ns:xmpp-sasl";
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<Success> {
return std::optional{Success{}};
}
static constexpr auto Parse(xmlpp::Element* element) -> Success {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const Success& failure) {
}
};
struct Abort : std::exception {
static constexpr auto kDefaultName = "abort";
static constexpr auto kDefaultNamespace = "urn:ietf:params:xml:ns:xmpp-sasl";
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<Abort> {
return element->get_first_child("aborted") ? std::optional{Abort{}} : std::nullopt;
}
static constexpr auto Parse(xmlpp::Element* element) -> Abort {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const Abort& failure) {
element->set_namespace_declaration("urn:ietf:params:xml:ns:xmpp-sasl");
}
[[nodiscard]] constexpr auto what() const noexcept -> const char* override {
return "Sasl Abort";
}
};
using Response = std::variant<Failure, Success, Abort>;
} // namespace larra::xmpp::client::sasl

View file

@ -0,0 +1,40 @@
#pragma once
#include <libxml++/libxml++.h>
#include <optional>
#include <variant>
namespace larra::xmpp::client::starttls {
struct Failure : std::exception {
static constexpr auto kDefaultName = "failure";
static constexpr auto kDefaultNamespace = "urn:ietf:params:xml:ns:xmpp-sasl";
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<Failure> {
return element->get_name() == kDefaultName ? std::optional{Failure{}} : std::nullopt;
}
static constexpr auto Parse(xmlpp::Element* element) -> Failure {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const Failure& failure) {
}
[[nodiscard]] constexpr auto what() const noexcept -> const char* override {
return "StartTLS Failure";
}
};
struct Success {
static constexpr auto kDefaultName = "success";
static constexpr auto kDefaultNamespace = "urn:ietf:params:xml:ns:xmpp-tls";
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<Success> {
return element->get_name() == kDefaultName ? std::optional{Success{}} : std::nullopt;
}
static constexpr auto Parse(xmlpp::Element* element) -> Success {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const Success& failure) {
}
};
using Response = std::variant<Failure, Success>;
} // namespace larra::xmpp::client::starttls

View file

@ -15,12 +15,12 @@ struct BareJid {
constexpr auto operator==(const BareJid&) const -> bool = default; constexpr auto operator==(const BareJid&) const -> bool = default;
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> BareJid { [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"username", BareJid>(std::forward<Self>(self), std::move(username)); return utils::FieldSetHelper::With<"username", BareJid>(std::forward<Self>(self), std::move(username));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> BareJid { [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"server", BareJid>(std::forward<Self>(self), std::move(server)); return utils::FieldSetHelper::With<"server", BareJid>(std::forward<Self>(self), std::move(server));
} }
}; };
@ -34,12 +34,12 @@ struct BareResourceJid {
constexpr auto operator==(const BareResourceJid&) const -> bool = default; constexpr auto operator==(const BareResourceJid&) const -> bool = default;
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> BareResourceJid { [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"server", BareResourceJid>(std::forward<Self>(self), std::move(server)); return utils::FieldSetHelper::With<"server", BareResourceJid>(std::forward<Self>(self), std::move(server));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> BareResourceJid { [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"resource", BareResourceJid>(std::forward<Self>(self), std::move(resource)); return utils::FieldSetHelper::With<"resource", BareResourceJid>(std::forward<Self>(self), std::move(resource));
} }
}; };
@ -54,17 +54,17 @@ struct FullJid {
constexpr auto operator==(const FullJid&) const -> bool = default; constexpr auto operator==(const FullJid&) const -> bool = default;
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> FullJid { [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"username", FullJid>(std::forward<Self>(self), std::move(username)); return utils::FieldSetHelper::With<"username", FullJid>(std::forward<Self>(self), std::move(username));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> FullJid { [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"server", FullJid>(std::forward<Self>(self), std::move(server)); return utils::FieldSetHelper::With<"server", FullJid>(std::forward<Self>(self), std::move(server));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> FullJid { [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"resource", FullJid>(std::forward<Self>(self), std::move(resource)); return utils::FieldSetHelper::With<"resource", FullJid>(std::forward<Self>(self), std::move(resource));
} }
}; };

View file

@ -48,11 +48,11 @@ struct Initial {
FullJid from; FullJid from;
BareJid to; BareJid to;
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> Initial { [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"from", Initial>(std::forward<Self>(self), std::move(value)); return utils::FieldSetHelper::With<"from", Initial>(std::forward<Self>(self), std::move(value));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> Initial { [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"to", Initial>(std::forward<Self>(self), std::move(value)); return utils::FieldSetHelper::With<"to", Initial>(std::forward<Self>(self), std::move(value));
} }
friend constexpr auto operator<<(xmlpp::Element* element, const Initial& presence) { friend constexpr auto operator<<(xmlpp::Element* element, const Initial& presence) {
@ -78,15 +78,15 @@ struct Probe {
BareJid to; BareJid to;
std::string id; std::string id;
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> Probe { [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"from", Probe>(std::forward<Self>(self), std::move(value)); return utils::FieldSetHelper::With<"from", Probe>(std::forward<Self>(self), std::move(value));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> Probe { [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"to", Probe>(std::forward<Self>(self), std::move(value)); return utils::FieldSetHelper::With<"to", Probe>(std::forward<Self>(self), std::move(value));
} }
template <typename Self> template <typename Self>
[[nodiscard]] constexpr auto Id(this Self&& self, std::string value) -> Probe { [[nodiscard]] constexpr auto Id(this Self&& self, std::string value) -> std::decay_t<Self> {
return utils::FieldSetHelper::With<"id", Probe>(std::forward<Self>(self), std::move(value)); return utils::FieldSetHelper::With<"id", Probe>(std::forward<Self>(self), std::move(value));
} }
friend constexpr auto operator<<(xmlpp::Element* element, const Probe& presence) { friend constexpr auto operator<<(xmlpp::Element* element, const Probe& presence) {

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <boost/pfr.hpp> #include <boost/pfr.hpp>
#include <ranges>
#include <utempl/utils.hpp> #include <utempl/utils.hpp>
namespace larra::xmpp::utils { namespace larra::xmpp::utils {
@ -54,7 +53,7 @@ struct FieldsDescription {
* \return an object of type std::decay_t<Self> with data from T with fields from \ref self and the \ref value of the field with index * \return an object of type std::decay_t<Self> with data from T with fields from \ref self and the \ref value of the field with index
* \ref I * \ref I
*/ */
template <std::size_t I, typename Self, typename Value> template <std::size_t I, typename Self, typename Value> // NOLINTNEXTLINE
constexpr auto With(Self&& self, Value&& value) const -> std::decay_t<Self> constexpr auto With(Self&& self, Value&& value) const -> std::decay_t<Self>
requires(std::constructible_from<std::decay_t<Self>, T> && std::is_constructible_v<T, impl::GetTypeT<Fs>...> && requires(std::constructible_from<std::decay_t<Self>, T> && std::is_constructible_v<T, impl::GetTypeT<Fs>...> &&
impl::SetConcept<Self, std::decay_t<Value>, Fs...> && impl::SetConcept<Self, std::decay_t<Value>, Fs...> &&
@ -84,9 +83,9 @@ struct FieldsDescription {
* \param value new value for field * \param value new value for field
* \return an object of type std::decay_t<Self> with data from T with fields from \ref self and the \ref value of the field \ref ptr * \return an object of type std::decay_t<Self> with data from T with fields from \ref self and the \ref value of the field \ref ptr
*/ */
template <typename Self, typename Value, typename Type> template <typename Self, typename Value, typename Type> // NOLINTNEXTLINE
constexpr auto With(Type(T::*ptr), Self&& self, Value&& value) const constexpr auto With(Type(T::* ptr), Self&& self, Value&& value) const -> std::decay_t<Self>
requires(std::is_constructible_v<T, impl::GetTypeT<Fs>...> && std::is_constructible_v<std::decay_t<Self>, T> && requires(std::is_constructible_v<T, impl::GetTypeT<Fs>...> && std::constructible_from<std::decay_t<Self>, T> &&
std::is_constructible_v<Type, decltype(value)> && impl::SetConcept<Self, Type, Fs...>) std::is_constructible_v<Type, decltype(value)> && impl::SetConcept<Self, Type, Fs...>)
{ {
return std::decay_t<Self>{utempl::Unpack(this->tuple, [&](auto... fs) -> T { return std::decay_t<Self>{utempl::Unpack(this->tuple, [&](auto... fs) -> T {
@ -165,14 +164,17 @@ struct FieldSetHelper {
*/ */
template <std::size_t I, template <std::size_t I,
typename T = void, typename T = void,
bool ConstructT = true,
typename Self, typename Self,
typename Value, typename Value,
typename..., typename...,
typename Type = std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>, typename Type = std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>,
typename TT = decltype(impl::GCCWorkaround<T, Self>())> typename TT = decltype(impl::GCCWorkaround<T, Self>())> // NOLINTNEXTLINE
static constexpr auto With(Self&& self, Value&& value) -> std::decay_t<Self> static constexpr auto With(Self&& self, Value&& value) -> std::conditional_t<ConstructT, std::decay_t<Self>, Type>
requires(std::constructible_from<std::decay_t<Self>, Type> && std::is_aggregate_v<Type> && requires(std::is_aggregate_v<Type> &&
(std::same_as<T, void> || requires { static_cast<const T&>(self); }) && I < boost::pfr::tuple_size_v<Type> && (!ConstructT || (std::constructible_from<std::decay_t<Self>, Type> &&
(std::same_as<T, void> || requires { static_cast<const T&>(self); }))) &&
I < boost::pfr::tuple_size_v<Type> &&
std::is_constructible_v<std::decay_t<decltype(boost::pfr::get<I>(std::declval<TT>()))>, decltype(value)> && std::is_constructible_v<std::decay_t<decltype(boost::pfr::get<I>(std::declval<TT>()))>, decltype(value)> &&
[](auto... is) { [](auto... is) {
return ((*is == I ? true return ((*is == I ? true
@ -182,12 +184,12 @@ struct FieldSetHelper {
std::is_constructible_v<Type, decltype(boost::pfr::get<*is>(std::declval<TT>()))...>; std::is_constructible_v<Type, decltype(boost::pfr::get<*is>(std::declval<TT>()))...>;
} | utempl::kSeq<boost::pfr::tuple_size_v<Type>>) } | utempl::kSeq<boost::pfr::tuple_size_v<Type>>)
{ {
return std::decay_t<Self>{[&](auto... is) -> Type { return std::conditional_t<ConstructT, std::decay_t<Self>, Type>{[&](auto... is) -> Type {
return {[&] -> decltype(auto) { return {[&] -> decltype(auto) {
if constexpr(I == *is) { if constexpr(I == *is) {
return std::forward<Value>(value); return std::forward<Value>(value);
} else { } else {
return std::forward_like<Self>(boost::pfr::get<*is>(static_cast<TT&>(self))); return std::forward_like<Self>(boost::pfr::get<*is>(static_cast<std::conditional_t<ConstructT, TT&, decltype(self)>>(self)));
} }
}()...}; }()...};
} | utempl::kSeq<boost::pfr::tuple_size_v<TT>>}; } | utempl::kSeq<boost::pfr::tuple_size_v<TT>>};
@ -203,15 +205,15 @@ struct FieldSetHelper {
* \returns an object of type std::decay_t<Self> with data from Type constructed with fields with \ref self and the \ref value of the field named \ref FieldName where Type is * \returns an object of type std::decay_t<Self> with data from Type constructed with fields with \ref self and the \ref value of the field named \ref FieldName where Type is
* std::conditional_t<std::same_as<\ref T, void>, std::decay_t<Self>, \ref T> * std::conditional_t<std::same_as<\ref T, void>, std::decay_t<Self>, \ref T>
*/ */
template <utempl::ConstexprString FieldName, typename T = void, typename Self, typename Value> template <utempl::ConstexprString FieldName, typename T = void, bool ConstructT = true, typename Self, typename Value>
static constexpr auto With(Self&& self, Value&& value) -> decltype(With<[] { static constexpr auto With(Self&& self, Value&& value) -> decltype(With<[] {
constexpr auto names = boost::pfr::names_as_array<std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>>(); constexpr auto names = boost::pfr::names_as_array<std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>>();
return std::ranges::find(names, static_cast<std::string_view>(FieldName)) - names.begin(); return std::ranges::find(names, static_cast<std::string_view>(FieldName)) - names.begin();
}(), }(),
T>(std::forward<Self>(self), std::forward<Value>(value))) { T, ConstructT>(std::forward<Self>(self), std::forward<Value>(value))) {
constexpr auto names = boost::pfr::names_as_array<std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>>(); constexpr auto names = boost::pfr::names_as_array<std::conditional_t<std::same_as<T, void>, std::decay_t<Self>, T>>();
constexpr auto id = std::ranges::find(names, static_cast<std::string_view>(FieldName)) - names.begin(); constexpr auto id = std::ranges::find(names, static_cast<std::string_view>(FieldName)) - names.begin();
return With<id, T>(std::forward<Self>(self), std::forward<Value>(value)); return With<id, T, ConstructT>(std::forward<Self>(self), std::forward<Value>(value));
}; };
// clang-format on // clang-format on
}; };

View file

@ -1,4 +1,5 @@
#include <larra/features.hpp> #include <larra/features.hpp>
#include <ranges>
namespace { namespace {

View file

@ -98,7 +98,7 @@ struct SomeStruct6 {
}; };
struct SomeStruct7 : SomeStruct6 { struct SomeStruct7 : SomeStruct6 {
SomeStruct7(SomeStruct6&& obj) : SomeStruct6(std::move(obj)) {}; explicit SomeStruct7(SomeStruct6&& obj) : SomeStruct6(std::move(obj)) {};
using SomeStruct6::SomeStruct6; using SomeStruct6::SomeStruct6;
}; };
@ -108,4 +108,18 @@ TEST(Set, Inheritance) {
ASSERT_EQ(obj.field2, "World"); ASSERT_EQ(obj.field2, "World");
} }
template <typename T>
struct SomeStruct8 {
T value;
template <typename TT, typename Self>
constexpr auto Value(this Self&& self, TT value) {
return utils::FieldSetHelper::With<0, SomeStruct8<TT>, false>(std::forward<Self>(self), std::move(value));
}
};
TEST(Set, OtherType) {
constexpr auto value = SomeStruct8{.value = 42}.Value<std::string_view>("Hello World");
EXPECT_EQ(value.value, std::string_view{"Hello World"});
}
} // namespace larra::xmpp } // namespace larra::xmpp