diff --git a/library/include/larra/stream.hpp b/library/include/larra/stream.hpp index e1d9d9a..3b824f9 100644 --- a/library/include/larra/stream.hpp +++ b/library/include/larra/stream.hpp @@ -1,50 +1,61 @@ -module; -c export module larra.library.stream; -export import larra.library.jid; -import larra.library.utils; -import std; +#pragma once +#include +#include namespace larra::xmpp { -export struct Stream { - std::optional from; - std::optional to; +namespace impl { + +template +struct BasicStream { + static constexpr bool kJidFrom = JidFrom; + static constexpr bool kJidTo = JidTo; + using FromType = std::optional>; + using ToType = std::optional>; + FromType from; + ToType to; std::optional id; std::optional version; std::optional xmlLang; template - constexpr auto From(this Self&& self, BareJid value) { + constexpr auto From(this Self&& self, FromType value) { return utils::FieldSetHelper::With<"from">(std::forward(self), std::move(value)); }; template - constexpr auto To(this Self&& self, BareJid value) { + constexpr auto To(this Self&& self, ToType value) { return utils::FieldSetHelper::With<"to">(std::forward(self), std::move(value)); }; template - constexpr auto Id(this Self&& self, std::string value) { + constexpr auto Id(this Self&& self, std::optional value) { return utils::FieldSetHelper::With<"id">(std::forward(self), std::move(value)); }; template - constexpr auto Version(this Self&& self, std::string value) { + constexpr auto Version(this Self&& self, std::optional value) { return utils::FieldSetHelper::With<"version">(std::forward(self), std::move(value)); }; template - constexpr auto XmlLang(this Self&& self, std::string value) { - return utils::FieldSetHelper::With<"xmlLang">(std::forward(self), std::move(value)); + constexpr auto XmlLang(this Self&& self, std::optional value) { + return utils::FieldSetHelper::With<"xmlLang">(std::forward_like(self), std::move(value)); }; - constexpr Stream(BareJid to) : to(std::move(to)), version("1.0") {}; - friend auto operator<<(pugi::xml_node& node, const Stream& stream) { - if(stream.from) { - auto str = ToString(*stream.from); - node.append_attribute("from") = str.c_str(); - }; + auto SerializeStream(pugi::xml_node& node) const -> void; + friend auto operator<<(pugi::xml_node& node, const BasicStream& stream) -> pugi::xml_node& { + return (stream.SerializeStream(node), node); }; + static auto Parse(const pugi::xml_node& node) -> BasicStream; }; +} // namespace impl + +using UserStream = impl::BasicStream; +using UserToUserStream = impl::BasicStream; + +using ServerStream = impl::BasicStream; +using ServerToUserStream = impl::BasicStream; + } // namespace larra::xmpp diff --git a/library/src/stream.cpp b/library/src/stream.cpp new file mode 100644 index 0000000..1c2e5b0 --- /dev/null +++ b/library/src/stream.cpp @@ -0,0 +1,64 @@ +#include + +namespace { + +inline auto ToOptionalString(const pugi::xml_attribute& attribute) -> std::optional { + return attribute ? std::optional{std::string{attribute.as_string()}} : std::nullopt; +} + +template +inline auto ToOptionalUser(const pugi::xml_attribute& attribute) { + if constexpr(IsJid) { + return attribute ? std::optional{larra::xmpp::BareJid::Parse(attribute.as_string())} : std::nullopt; + } else { + return attribute ? std::optional{std::string{attribute.as_string()}} : std::nullopt; + } +} + +auto ToString(std::string data) -> std::string { + return std::move(data); +}; + +} // namespace + +namespace larra::xmpp { + +template +auto impl::BasicStream::SerializeStream(pugi::xml_node& node) const -> void { + if(this->from) { + node.append_attribute("from") = ToString(*this->from).c_str(); + } + if(this->to) { + node.append_attribute("to") = ToString(*this->to).c_str(); + } + if(this->id) { + node.append_attribute("id") = this->id->c_str(); + } + if(this->version) { + node.append_attribute("version") = this->version->c_str(); + } + if(this->xmlLang) { + node.append_attribute("xml:lang") = this->xmlLang->c_str(); + } +} + +template auto ServerStream::SerializeStream(pugi::xml_node& node) const -> void; +template auto ServerToUserStream::SerializeStream(pugi::xml_node& node) const -> void; + +template auto UserToUserStream::SerializeStream(pugi::xml_node& node) const -> void; +template auto UserStream::SerializeStream(pugi::xml_node& node) const -> void; + +template +auto impl::BasicStream::Parse(const pugi::xml_node& node) -> impl::BasicStream { + return {ToOptionalUser(node.attribute("from")), + ToOptionalUser(node.attribute("to")), + ToOptionalString(node.attribute("id")), + ToOptionalString(node.attribute("version")), + ToOptionalString(node.attribute("xml:lang"))}; +} +template auto UserStream::Parse(const pugi::xml_node& node) -> UserStream; +template auto UserToUserStream::Parse(const pugi::xml_node& node) -> UserToUserStream; + +template auto ServerStream::Parse(const pugi::xml_node& node) -> ServerStream; +template auto ServerToUserStream::Parse(const pugi::xml_node& node) -> ServerToUserStream; +} // namespace larra::xmpp diff --git a/tests/stream.cpp b/tests/stream.cpp new file mode 100644 index 0000000..ea460a0 --- /dev/null +++ b/tests/stream.cpp @@ -0,0 +1,54 @@ +#include + +#include + +namespace larra::xmpp { + +constexpr std::string_view kSerializedData = + R"( +)"; + +constexpr std::string_view kCheckSerializeData = + R"( +)"; + +TEST(Stream, Serialize) { + UserToUserStream originalStream; + originalStream.from = BareJid{"user", "example.com"}; + originalStream.to = BareJid{"anotheruser", "example.com"}; + originalStream.id = "abc"; + originalStream.version = "1.0"; + originalStream.xmlLang = "en"; + + pugi::xml_document doc; + pugi::xml_node streamNode = doc.append_child("stream:stream"); + streamNode << originalStream; + + std::ostringstream oss; + doc.child("stream:stream").print(oss, "\t"); + const std::string serializedData = oss.str(); + + ASSERT_EQ(serializedData, kCheckSerializeData); +} + +TEST(Stream, Deserialize) { + pugi::xml_document parsedDoc; + parsedDoc.load_string(kSerializedData.data()); + + const UserStream deserializedStream = UserStream::Parse(parsedDoc.child("stream:stream")); + ASSERT_TRUE(deserializedStream.from.has_value()); + ASSERT_EQ(ToString(*deserializedStream.from), "user@example.com"); + + ASSERT_FALSE(deserializedStream.to.has_value()); + + ASSERT_TRUE(deserializedStream.id.has_value()); + ASSERT_EQ(deserializedStream.id.value(), "abc"); + + ASSERT_TRUE(deserializedStream.version.has_value()); + ASSERT_EQ(deserializedStream.version.value(), "1.0"); + + ASSERT_TRUE(deserializedStream.xmlLang.has_value()); + ASSERT_EQ(deserializedStream.xmlLang.value(), "en"); +} + +} // namespace larra::xmpp