diff --git a/src/lib/jid.cpp b/src/lib/jid.cpp new file mode 100644 index 0000000..21f5b33 --- /dev/null +++ b/src/lib/jid.cpp @@ -0,0 +1,75 @@ +export module larra.library.jid; +import std; +import fmt; + +namespace larra::xmpp { + +export struct Jid { + [[nodiscard]] static auto Parse(std::string_view jid) -> Jid { + Jid response; + const auto at = jid.find('@'); + const auto slash = jid.find('/', at == std::string_view::npos ? 0 : at); + + if(at != std::string_view::npos) { + response.username = jid.substr(0, at); + response.server = jid.substr(at + 1, (slash == std::string_view::npos ? jid.size() : slash) - (at + 1)); + } else { + response.server = jid.substr(0, slash); + } + + if(slash != std::string_view::npos) { + response.resource = jid.substr(slash + 1); + } + + return response; + } + + template + [[nodiscard]] auto Username(this Self&& self, std::string username) -> Jid { + return {std::forward_like(self.server), std::move(username), std::forward_like(self.resource)}; + } + + template + [[nodiscard]] auto Server(this Self&& self, std::string server) -> Jid { + return {std::move(server), std::forward_like(self.username), std::forward_like(self.resource)}; + } + + template + [[nodiscard]] auto Resource(this Self&& self, std::string resource) -> Jid { + return {std::forward_like(self.server), std::forward_like(self.username), std::move(resource)}; + } + + [[nodiscard]] auto IsValid() const -> bool { + return this->server && this->username || this->resource; + } + + [[nodiscard]] auto Username() const -> std::string_view { + return *this->username; + } + + [[nodiscard]] auto Server() const -> std::string_view { + return *this->server; + } + + [[nodiscard]] auto Resource() const -> std::string_view { + return *this->resource; + } + + [[nodiscard]] explicit operator std::string() const { + if(!IsValid()) { + throw std::invalid_argument("Invalid jid obj"); + } + return !this->username ? std::format("{}/{}", *this->server, *this->resource) + : !this->resource ? std::format("{}@{}", *this->username, *this->server) + : std::format("{}@{}/{}", *this->username, *this->server, *this->resource); + } + [[nodiscard]] auto ToString() const -> std::string { + return static_cast(*this); + }; + + std::optional server{}; + std::optional username{}; + std::optional resource{}; +}; + +} // namespace larra::xmpp diff --git a/src/lib/library.cpp b/src/lib/library.cpp index 79cac43..dd919bf 100644 --- a/src/lib/library.cpp +++ b/src/lib/library.cpp @@ -1 +1,2 @@ export module larra.library; +export import larra.jid; diff --git a/tests/jid.cpp b/tests/jid.cpp new file mode 100644 index 0000000..65f8383 --- /dev/null +++ b/tests/jid.cpp @@ -0,0 +1,37 @@ +module; +#include +export module tests.jid; +import larra.library.jid; + +namespace larra::xmpp { + +TEST(Jid, Basic) { + auto jid = Jid{.username = "user"}; + EXPECT_FALSE(jid.IsValid()); + + const auto jid2 = std::move(jid).Server("server").Resource("resource"); + EXPECT_EQ(jid2.Server(), "server"); + EXPECT_EQ(jid2.Username(), "user"); + EXPECT_EQ(jid2.Resource(), "resource"); +} + +TEST(Jid, Parse) { + const auto jid = Jid::Parse("user@server/resource"); + EXPECT_EQ(jid.Username(), "user"); + EXPECT_EQ(jid.Server(), "server"); + EXPECT_EQ(jid.Resource(), "resource"); + const auto jid2 = Jid::Parse("server/resource"); + EXPECT_EQ(jid2.Server(), "server"); + EXPECT_EQ(jid2.Resource(), "resource"); + const auto jid3 = Jid::Parse("user@server"); + EXPECT_EQ(jid3.Username(), "user"); + EXPECT_EQ(jid3.Server(), "server"); +} + +TEST(Jid, ToString) { + EXPECT_EQ((Jid{.server = "server", .username = "user", .resource = "resource"}.ToString()), "user@server/resource"); + EXPECT_EQ((Jid{.server = "server", .username = "user"}.ToString()), "user@server"); + EXPECT_THROW(std::ignore = Jid{}.ToString(), std::invalid_argument); +} + +} // namespace larra::xmpp