2021-03-10 21:05:49 +03:00
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// Licensed under the Apache 2.0 License.
|
|
|
|
#pragma once
|
|
|
|
|
2022-02-11 12:35:38 +03:00
|
|
|
#include "ccf/ds/json.h"
|
2022-02-28 17:38:25 +03:00
|
|
|
#include "ccf/kv/serialisers/blit_serialiser.h"
|
2021-03-10 21:05:49 +03:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace ccf
|
|
|
|
{
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender = void>
|
2021-03-10 21:05:49 +03:00
|
|
|
struct EntityId
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// The underlying value type should be blit-serialisable so that it can be
|
|
|
|
// written to and read from the ring buffer
|
|
|
|
static constexpr size_t LENGTH = 64; // hex-encoded SHA-256 hash
|
|
|
|
using Value = std::string; // < hex-encoded hash
|
|
|
|
|
|
|
|
private:
|
|
|
|
Value id;
|
|
|
|
|
|
|
|
public:
|
|
|
|
EntityId() = default;
|
2021-06-28 13:15:23 +03:00
|
|
|
EntityId(const EntityId& id_) = default;
|
2021-03-10 21:05:49 +03:00
|
|
|
EntityId(const Value& id_) : id(id_) {}
|
2021-03-18 14:25:55 +03:00
|
|
|
EntityId(Value&& id_) : id(std::move(id_)) {}
|
2021-03-10 21:05:49 +03:00
|
|
|
|
2021-04-16 21:20:37 +03:00
|
|
|
inline operator std::string() const
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2021-03-10 21:05:49 +03:00
|
|
|
void operator=(const EntityId& other)
|
|
|
|
{
|
|
|
|
id = other.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator=(const Value& id_)
|
|
|
|
{
|
|
|
|
id = id_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const EntityId& other) const
|
|
|
|
{
|
|
|
|
return id == other.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const EntityId& other) const
|
|
|
|
{
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator<(const EntityId& other) const
|
|
|
|
{
|
|
|
|
return id < other.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value& value()
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Value& value() const
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* data() const
|
|
|
|
{
|
|
|
|
return id.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
{
|
|
|
|
return id.size();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
|
|
|
inline void to_json(nlohmann::json& j, const EntityId<FmtExtender>& entity_id)
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
|
|
|
j = entity_id.value();
|
|
|
|
}
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
|
|
|
inline void from_json(
|
|
|
|
const nlohmann::json& j, EntityId<FmtExtender>& entity_id)
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
|
|
|
if (j.is_string())
|
|
|
|
{
|
|
|
|
entity_id = j.get<std::string>();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-06-19 19:23:03 +03:00
|
|
|
throw ccf::JsonParseError(fmt::format(
|
2022-03-02 12:46:47 +03:00
|
|
|
"{} should be hex-encoded string: {}",
|
|
|
|
FmtExtender::ID_LABEL,
|
|
|
|
j.dump()));
|
2021-03-10 21:05:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
2022-04-27 13:01:22 +03:00
|
|
|
inline std::string schema_name(const EntityId<FmtExtender>*)
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
2022-03-02 12:46:47 +03:00
|
|
|
return FmtExtender::ID_LABEL;
|
2021-03-10 21:05:49 +03:00
|
|
|
}
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
|
|
|
inline void fill_json_schema(
|
2022-04-27 13:01:22 +03:00
|
|
|
nlohmann::json& schema, const EntityId<FmtExtender>*)
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
|
|
|
schema["type"] = "string";
|
|
|
|
|
|
|
|
// According to the spec, "format is an open value, so you can use any
|
|
|
|
// formats, even not those defined by the OpenAPI Specification"
|
|
|
|
// https://swagger.io/docs/specification/data-models/data-types/#format
|
|
|
|
schema["format"] = "hex";
|
2021-06-03 10:39:32 +03:00
|
|
|
schema["pattern"] =
|
|
|
|
fmt::format("^[a-f0-9]{{{}}}$", EntityId<FmtExtender>::LENGTH);
|
2021-03-10 21:05:49 +03:00
|
|
|
}
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
struct MemberIdFormatter
|
|
|
|
{
|
|
|
|
static std::string format(const std::string& core)
|
|
|
|
{
|
|
|
|
return fmt::format("m[{}]", core);
|
|
|
|
}
|
2022-03-02 12:46:47 +03:00
|
|
|
|
|
|
|
static constexpr auto ID_LABEL = "MemberId";
|
2021-06-03 10:39:32 +03:00
|
|
|
};
|
|
|
|
using MemberId = EntityId<MemberIdFormatter>;
|
|
|
|
|
|
|
|
struct UserIdFormatter
|
|
|
|
{
|
|
|
|
static std::string format(const std::string& core)
|
|
|
|
{
|
|
|
|
return fmt::format("u[{}]", core);
|
|
|
|
}
|
2022-03-02 12:46:47 +03:00
|
|
|
|
|
|
|
static constexpr auto ID_LABEL = "UserId";
|
2021-06-03 10:39:32 +03:00
|
|
|
};
|
|
|
|
using UserId = EntityId<UserIdFormatter>;
|
|
|
|
|
|
|
|
struct NodeIdFormatter
|
|
|
|
{
|
|
|
|
static std::string format(const std::string& core)
|
|
|
|
{
|
|
|
|
return fmt::format("n[{}]", core);
|
|
|
|
}
|
2022-03-02 12:46:47 +03:00
|
|
|
|
|
|
|
static constexpr auto ID_LABEL = "NodeId";
|
2021-06-03 10:39:32 +03:00
|
|
|
};
|
|
|
|
using NodeId = EntityId<NodeIdFormatter>;
|
2021-03-10 21:05:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace std
|
|
|
|
{
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
2021-03-10 21:05:49 +03:00
|
|
|
static inline std::ostream& operator<<(
|
2021-06-03 10:39:32 +03:00
|
|
|
std::ostream& os, const ccf::EntityId<FmtExtender>& entity_id)
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
2021-06-03 10:39:32 +03:00
|
|
|
if constexpr (std::is_same_v<FmtExtender, void>)
|
|
|
|
{
|
|
|
|
os << entity_id.value();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
os << FmtExtender::format(entity_id.value());
|
|
|
|
}
|
2021-03-10 21:05:49 +03:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2021-06-03 10:39:32 +03:00
|
|
|
template <typename FmtExtender>
|
|
|
|
struct hash<ccf::EntityId<FmtExtender>>
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
2021-06-03 10:39:32 +03:00
|
|
|
size_t operator()(const ccf::EntityId<FmtExtender>& entity_id) const
|
2021-03-10 21:05:49 +03:00
|
|
|
{
|
|
|
|
return std::hash<std::string>{}(entity_id.value());
|
|
|
|
}
|
|
|
|
};
|
2021-07-05 11:45:13 +03:00
|
|
|
}
|
|
|
|
|
2022-02-18 12:22:36 +03:00
|
|
|
FMT_BEGIN_NAMESPACE
|
|
|
|
template <typename FmtExtender>
|
|
|
|
struct formatter<ccf::EntityId<FmtExtender>>
|
2021-07-05 11:45:13 +03:00
|
|
|
{
|
2022-02-18 12:22:36 +03:00
|
|
|
template <typename ParseContext>
|
|
|
|
constexpr auto parse(ParseContext& ctx)
|
2021-07-05 11:45:13 +03:00
|
|
|
{
|
2022-02-18 12:22:36 +03:00
|
|
|
return ctx.begin();
|
|
|
|
}
|
2021-07-05 11:45:13 +03:00
|
|
|
|
2022-02-18 12:22:36 +03:00
|
|
|
template <typename FormatContext>
|
2022-08-15 17:01:53 +03:00
|
|
|
auto format(const ccf::EntityId<FmtExtender>& v, FormatContext& ctx) const
|
2022-02-18 12:22:36 +03:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << v;
|
|
|
|
return format_to(ctx.out(), "{}", ss.str());
|
|
|
|
}
|
|
|
|
};
|
2022-02-28 17:38:25 +03:00
|
|
|
FMT_END_NAMESPACE
|
|
|
|
|
2024-06-28 17:42:49 +03:00
|
|
|
namespace ccf::kv::serialisers
|
2022-02-28 17:38:25 +03:00
|
|
|
{
|
|
|
|
template <typename FmtExtender>
|
|
|
|
struct BlitSerialiser<ccf::EntityId<FmtExtender>>
|
|
|
|
{
|
|
|
|
static SerialisedEntry to_serialised(
|
|
|
|
const ccf::EntityId<FmtExtender>& entity_id)
|
|
|
|
{
|
|
|
|
const auto& data = entity_id.value();
|
|
|
|
return SerialisedEntry(data.begin(), data.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
static ccf::EntityId<FmtExtender> from_serialised(
|
|
|
|
const SerialisedEntry& data)
|
|
|
|
{
|
|
|
|
return ccf::EntityId<FmtExtender>(std::string(data.begin(), data.end()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|