diff --git a/.gitignore b/.gitignore index 4028266..d52f86a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ ext/ libxmlplusplus-prefix/ spdlog.pc build* +larra diff --git a/library/include/larra/client/challenge_response.hpp b/library/include/larra/client/challenge_response.hpp new file mode 100644 index 0000000..bfbbe83 --- /dev/null +++ b/library/include/larra/client/challenge_response.hpp @@ -0,0 +1,74 @@ +#pragma once +#include + +#include +#include +#include + +namespace larra::xmpp::client::sasl { + +struct Failure : std::exception { + std::optional text; + constexpr Failure(std::optional 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 { + return std::optional{Failure{[&] -> std::optional { + auto textNode = element->get_first_child("text"); + if(!textNode) { + return std::nullopt; + } + auto text = dynamic_cast(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 { + 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 { + 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; + +} // namespace larra::xmpp::client::sasl diff --git a/library/include/larra/client/starttls_response.hpp b/library/include/larra/client/starttls_response.hpp new file mode 100644 index 0000000..46fe407 --- /dev/null +++ b/library/include/larra/client/starttls_response.hpp @@ -0,0 +1,40 @@ +#pragma once +#include + +#include +#include + +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 { + 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 { + 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; + +} // namespace larra::xmpp::client::starttls diff --git a/library/include/larra/jid.hpp b/library/include/larra/jid.hpp index 567f196..78fa043 100644 --- a/library/include/larra/jid.hpp +++ b/library/include/larra/jid.hpp @@ -15,12 +15,12 @@ struct BareJid { constexpr auto operator==(const BareJid&) const -> bool = default; template - [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> BareJid { + [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> std::decay_t { return utils::FieldSetHelper::With<"username", BareJid>(std::forward(self), std::move(username)); } template - [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> BareJid { + [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t { return utils::FieldSetHelper::With<"server", BareJid>(std::forward(self), std::move(server)); } }; @@ -34,12 +34,12 @@ struct BareResourceJid { constexpr auto operator==(const BareResourceJid&) const -> bool = default; template - [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> BareResourceJid { + [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t { return utils::FieldSetHelper::With<"server", BareResourceJid>(std::forward(self), std::move(server)); } template - [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> BareResourceJid { + [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> std::decay_t { return utils::FieldSetHelper::With<"resource", BareResourceJid>(std::forward(self), std::move(resource)); } }; @@ -54,17 +54,17 @@ struct FullJid { constexpr auto operator==(const FullJid&) const -> bool = default; template - [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> FullJid { + [[nodiscard]] constexpr auto Username(this Self&& self, std::string username) -> std::decay_t { return utils::FieldSetHelper::With<"username", FullJid>(std::forward(self), std::move(username)); } template - [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> FullJid { + [[nodiscard]] constexpr auto Server(this Self&& self, std::string server) -> std::decay_t { return utils::FieldSetHelper::With<"server", FullJid>(std::forward(self), std::move(server)); } template - [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> FullJid { + [[nodiscard]] constexpr auto Resource(this Self&& self, std::string resource) -> std::decay_t { return utils::FieldSetHelper::With<"resource", FullJid>(std::forward(self), std::move(resource)); } }; diff --git a/library/include/larra/presence.hpp b/library/include/larra/presence.hpp index ae8b705..abe61a7 100644 --- a/library/include/larra/presence.hpp +++ b/library/include/larra/presence.hpp @@ -48,11 +48,11 @@ struct Initial { FullJid from; BareJid to; template - [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> Initial { + [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> std::decay_t { return utils::FieldSetHelper::With<"from", Initial>(std::forward(self), std::move(value)); } template - [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> Initial { + [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> std::decay_t { return utils::FieldSetHelper::With<"to", Initial>(std::forward(self), std::move(value)); } friend constexpr auto operator<<(xmlpp::Element* element, const Initial& presence) { @@ -78,15 +78,15 @@ struct Probe { BareJid to; std::string id; template - [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> Probe { + [[nodiscard]] constexpr auto From(this Self&& self, BareJid value) -> std::decay_t { return utils::FieldSetHelper::With<"from", Probe>(std::forward(self), std::move(value)); } template - [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> Probe { + [[nodiscard]] constexpr auto To(this Self&& self, BareJid value) -> std::decay_t { return utils::FieldSetHelper::With<"to", Probe>(std::forward(self), std::move(value)); } template - [[nodiscard]] constexpr auto Id(this Self&& self, std::string value) -> Probe { + [[nodiscard]] constexpr auto Id(this Self&& self, std::string value) -> std::decay_t { return utils::FieldSetHelper::With<"id", Probe>(std::forward(self), std::move(value)); } friend constexpr auto operator<<(xmlpp::Element* element, const Probe& presence) { diff --git a/library/include/larra/utils.hpp b/library/include/larra/utils.hpp index 65bcefb..bca4277 100644 --- a/library/include/larra/utils.hpp +++ b/library/include/larra/utils.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include namespace larra::xmpp::utils { @@ -8,7 +7,7 @@ namespace larra::xmpp::utils { namespace impl { template -constexpr auto GetType(R(T::*ptr)) -> R; +constexpr auto GetType(R(T::* ptr)) -> R; template using GetTypeT = decltype(GetType(std::declval())); @@ -54,7 +53,7 @@ struct FieldsDescription { * \return an object of type std::decay_t with data from T with fields from \ref self and the \ref value of the field with index * \ref I */ - template + template // NOLINTNEXTLINE constexpr auto With(Self&& self, Value&& value) const -> std::decay_t requires(std::constructible_from, T> && std::is_constructible_v...> && impl::SetConcept, Fs...> && @@ -84,9 +83,9 @@ struct FieldsDescription { * \param value new value for field * \return an object of type std::decay_t with data from T with fields from \ref self and the \ref value of the field \ref ptr */ - template - constexpr auto With(Type(T::*ptr), Self&& self, Value&& value) const - requires(std::is_constructible_v...> && std::is_constructible_v, T> && + template // NOLINTNEXTLINE + constexpr auto With(Type(T::* ptr), Self&& self, Value&& value) const -> std::decay_t + requires(std::is_constructible_v...> && std::constructible_from, T> && std::is_constructible_v && impl::SetConcept) { return std::decay_t{utempl::Unpack(this->tuple, [&](auto... fs) -> T { @@ -165,14 +164,17 @@ struct FieldSetHelper { */ template , std::decay_t, T>, - typename TT = decltype(impl::GCCWorkaround())> - static constexpr auto With(Self&& self, Value&& value) -> std::decay_t - requires(std::constructible_from, Type> && std::is_aggregate_v && - (std::same_as || requires { static_cast(self); }) && I < boost::pfr::tuple_size_v && + typename TT = decltype(impl::GCCWorkaround())> // NOLINTNEXTLINE + static constexpr auto With(Self&& self, Value&& value) -> std::conditional_t, Type> + requires(std::is_aggregate_v && + (!ConstructT || (std::constructible_from, Type> && + (std::same_as || requires { static_cast(self); }))) && + I < boost::pfr::tuple_size_v && std::is_constructible_v(std::declval()))>, decltype(value)> && [](auto... is) { return ((*is == I ? true @@ -182,12 +184,12 @@ struct FieldSetHelper { std::is_constructible_v(std::declval()))...>; } | utempl::kSeq>) { - return std::decay_t{[&](auto... is) -> Type { + return std::conditional_t, Type>{[&](auto... is) -> Type { return {[&] -> decltype(auto) { if constexpr(I == *is) { return std::forward(value); } else { - return std::forward_like(boost::pfr::get<*is>(static_cast(self))); + return std::forward_like(boost::pfr::get<*is>(static_cast>(self))); } }()...}; } | utempl::kSeq>}; @@ -203,15 +205,15 @@ struct FieldSetHelper { * \returns an object of type std::decay_t 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::decay_t, \ref T> */ - template + template static constexpr auto With(Self&& self, Value&& value) -> decltype(With<[] { constexpr auto names = boost::pfr::names_as_array, std::decay_t, T>>(); return std::ranges::find(names, static_cast(FieldName)) - names.begin(); }(), - T>(std::forward(self), std::forward(value))) { + T, ConstructT>(std::forward(self), std::forward(value))) { constexpr auto names = boost::pfr::names_as_array, std::decay_t, T>>(); constexpr auto id = std::ranges::find(names, static_cast(FieldName)) - names.begin(); - return With(std::forward(self), std::forward(value)); + return With(std::forward(self), std::forward(value)); }; // clang-format on }; diff --git a/library/src/features.cpp b/library/src/features.cpp index 3849b37..dedd283 100644 --- a/library/src/features.cpp +++ b/library/src/features.cpp @@ -1,4 +1,5 @@ #include +#include namespace { diff --git a/tests/set.cpp b/tests/set.cpp index 699a579..c872058 100644 --- a/tests/set.cpp +++ b/tests/set.cpp @@ -98,7 +98,7 @@ struct SomeStruct6 { }; struct SomeStruct7 : SomeStruct6 { - SomeStruct7(SomeStruct6&& obj) : SomeStruct6(std::move(obj)) {}; + explicit SomeStruct7(SomeStruct6&& obj) : SomeStruct6(std::move(obj)) {}; using SomeStruct6::SomeStruct6; }; @@ -108,4 +108,18 @@ TEST(Set, Inheritance) { ASSERT_EQ(obj.field2, "World"); } +template +struct SomeStruct8 { + T value; + template + constexpr auto Value(this Self&& self, TT value) { + return utils::FieldSetHelper::With<0, SomeStruct8, false>(std::forward(self), std::move(value)); + } +}; + +TEST(Set, OtherType) { + constexpr auto value = SomeStruct8{.value = 42}.Value("Hello World"); + EXPECT_EQ(value.value, std::string_view{"Hello World"}); +} + } // namespace larra::xmpp