Update Jid

This commit is contained in:
sha512sum 2024-08-27 11:53:22 +00:00
parent 52ec88216c
commit 945b44e0e4
3 changed files with 153 additions and 71 deletions

View file

@ -4,72 +4,144 @@ import fmt;
namespace larra::xmpp {
export struct Jid {
[[nodiscard]] static auto Parse(std::string_view jid) -> Jid {
Jid response;
export struct BareJid;
auto ParseBareJid(std::string_view, std::size_t) -> BareJid;
export struct BareJid {
std::string username;
std::string server;
[[nodiscard]] friend auto ToString(const BareJid& jid) -> std::string {
return std::format("{}@{}", jid.username, jid.server);
}
template <typename Self>
[[nodiscard]] auto Username(this Self&& self, std::string username) -> BareJid {
return {std::move(username), std::forward_like<Self>(self.resource)};
}
template <typename Self>
[[nodiscard]] auto Server(this Self&& self, std::string server) -> BareJid {
return {std::forward_like<Self>(self.server), std::move(server)};
}
[[nodiscard]] static auto Parse(std::string_view jid) -> BareJid {
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(at == std::string_view::npos) {
throw std::invalid_argument("Invalid string for jid");
}
if(slash != std::string_view::npos) {
response.resource = jid.substr(slash + 1);
}
return response;
return ParseBareJid(jid, at);
}
};
template <typename Self>
[[nodiscard]] auto Username(this Self&& self, std::string username) -> Jid {
return {std::forward_like<Self>(self.server), std::move(username), std::forward_like<Self>(self.resource)};
}
auto ParseBareJid(std::string_view jid, std::size_t at) -> BareJid {
return {static_cast<std::string>(jid.substr(0, at)), static_cast<std::string>(jid.substr(at + 1))};
}
template <typename Self>
[[nodiscard]] auto Server(this Self&& self, std::string server) -> Jid {
return {std::move(server), std::forward_like<Self>(self.username), std::forward_like<Self>(self.resource)};
}
export struct BareResourceJid;
template <typename Self>
[[nodiscard]] auto Resource(this Self&& self, std::string resource) -> Jid {
return {std::forward_like<Self>(self.server), std::forward_like<Self>(self.username), std::move(resource)};
}
auto ParseBareResourceJid(std::string_view, std::size_t) -> BareResourceJid;
[[nodiscard]] auto IsValid() const -> bool {
return this->server && this->username || this->resource;
}
export struct BareResourceJid {
std::string server;
std::string 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<std::string>(*this);
[[nodiscard]] friend auto ToString(const BareResourceJid& jid) -> std::string {
return std::format("{}/{}", jid.server, jid.resource);
};
std::optional<std::string> server{};
std::optional<std::string> username{};
std::optional<std::string> resource{};
template <typename Self>
[[nodiscard]] auto Server(this Self&& self, std::string server) -> BareResourceJid {
return {std::move(server), std::forward_like<Self>(self.resource)};
};
template <typename Self>
[[nodiscard]] auto Resource(this Self&& self, std::string resource) -> BareResourceJid {
return {std::forward_like<Self>(self.server), std::move(resource)};
};
[[nodiscard]] static auto Parse(std::string_view jid) -> BareResourceJid {
const auto slash = jid.find('/');
if(slash == std::string_view::npos) {
throw std::invalid_argument("Invalid string for jid");
};
return ParseBareResourceJid(jid, slash);
};
};
auto ParseBareResourceJid(std::string_view jid, std::size_t slash) -> BareResourceJid {
return {static_cast<std::string>(jid.substr(0, slash)), static_cast<std::string>(jid.substr(slash + 1))};
}
export struct FullJid;
auto ParseFullJid(std::string_view jid, std::size_t at, std::size_t slash) -> FullJid;
export struct FullJid {
std::string username;
std::string server;
std::string resource;
[[nodiscard]] friend auto ToString(const FullJid& jid) -> std::string {
return std::format("{}@{}/{}", jid.username, jid.server, jid.resource);
};
template <typename Self>
[[nodiscard]] auto Username(this Self&& self, std::string username) -> FullJid {
return {std::move(username), std::forward_like<Self>(self.server), std::forward_like<Self>(self.resource)};
};
template <typename Self>
[[nodiscard]] auto Server(this Self&& self, std::string server) -> FullJid {
return {std::forward_like<Self>(self.username), std::move(server), std::forward_like<Self>(self.resource)};
};
template <typename Self>
[[nodiscard]] auto Resource(this Self&& self, std::string resource) -> FullJid {
return {std::forward_like<Self>(self.username), std::forward_like<Self>(self.server), std::move(resource)};
};
[[nodiscard]] static auto Parse(std::string_view jid) -> FullJid {
const auto at = jid.find('@');
const auto slash = jid.find('/', at);
if(at == std::string_view::npos || slash == std::string_view::npos) {
throw std::invalid_argument("Invalid string for jid");
};
return ParseFullJid(jid, at, slash);
};
};
auto ParseFullJid(std::string_view jid, std::size_t at, std::size_t slash) -> FullJid {
return {static_cast<std::string>(jid.substr(0, at)),
static_cast<std::string>(jid.substr(at + 1, slash - at - 1)),
static_cast<std::string>(jid.substr(slash + 1))};
}
using JidVariant = std::variant<BareJid, BareResourceJid, FullJid>;
export struct Jid : JidVariant {
using JidVariant::variant;
[[nodiscard]] static auto Parse(std::string_view jid) -> Jid {
const auto at = jid.find('@');
const auto slash = jid.find('/', at == std::string_view::npos ? 0 : at);
if(at == std::string_view::npos) {
return ParseBareResourceJid(jid, slash);
}
if(slash == std::string_view::npos) {
return ParseBareJid(jid, at);
}
return ParseFullJid(jid, at, slash);
}
[[nodiscard]] friend auto ToString(const Jid& jid) -> std::string {
return std::visit<std::string>(
[](const auto& jid) -> std::string {
return ToString(jid);
},
jid);
};
};
} // namespace larra::xmpp

View file

@ -1,2 +1,2 @@
export module larra.library;
export import larra.jid;
export import larra.library.jid;

View file

@ -6,32 +6,42 @@ import larra.library.jid;
namespace larra::xmpp {
TEST(Jid, Basic) {
auto jid = Jid{.username = "user"};
EXPECT_FALSE(jid.IsValid());
auto jid = FullJid{.username = "user"};
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");
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");
EXPECT_TRUE(std::get_if<FullJid>(&jid));
const auto& fullJid = std::get<FullJid>(jid);
EXPECT_EQ(fullJid.username, "user");
EXPECT_EQ(fullJid.server, "server");
EXPECT_EQ(fullJid.resource, "resource");
const auto jid2 = Jid::Parse("server/resource");
EXPECT_EQ(jid2.Server(), "server");
EXPECT_EQ(jid2.Resource(), "resource");
EXPECT_TRUE(std::get_if<BareResourceJid>(&jid2));
const auto& resourceJid = std::get<BareResourceJid>(jid2);
EXPECT_EQ(resourceJid.server, "server");
EXPECT_EQ(resourceJid.resource, "resource");
const auto jid3 = Jid::Parse("user@server");
EXPECT_EQ(jid3.Username(), "user");
EXPECT_EQ(jid3.Server(), "server");
EXPECT_TRUE(std::get_if<BareJid>(&jid3));
const auto& bareJid = std::get<BareJid>(jid3);
EXPECT_EQ(bareJid.username, "user");
EXPECT_EQ(bareJid.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);
EXPECT_EQ(ToString(FullJid{.username = "user", .server = "server", .resource = "resource"}), "user@server/resource");
EXPECT_EQ(ToString(BareJid{.username = "user", .server = "server"}), "user@server");
EXPECT_EQ(ToString(BareResourceJid{.server = "server", .resource = "resource"}), "server/resource");
}
} // namespace larra::xmpp