CCF/include/ccf/entity_id.h

223 строки
4.8 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once
#include "ccf/ds/json.h"
#include "ccf/kv/serialisers/blit_serialiser.h"
#include <string>
namespace ccf
{
template <typename FmtExtender = void>
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;
EntityId(const EntityId& id_) = default;
EntityId(const Value& id_) : id(id_) {}
EntityId(Value&& id_) : id(std::move(id_)) {}
inline operator std::string() const
{
return id;
}
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();
}
};
template <typename FmtExtender>
inline void to_json(nlohmann::json& j, const EntityId<FmtExtender>& entity_id)
{
j = entity_id.value();
}
template <typename FmtExtender>
inline void from_json(
const nlohmann::json& j, EntityId<FmtExtender>& entity_id)
{
if (j.is_string())
{
entity_id = j.get<std::string>();
}
else
{
throw ccf::JsonParseError(fmt::format(
"{} should be hex-encoded string: {}",
FmtExtender::ID_LABEL,
j.dump()));
}
}
template <typename FmtExtender>
inline std::string schema_name(const EntityId<FmtExtender>*)
{
return FmtExtender::ID_LABEL;
}
template <typename FmtExtender>
inline void fill_json_schema(
nlohmann::json& schema, const EntityId<FmtExtender>*)
{
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";
schema["pattern"] =
fmt::format("^[a-f0-9]{{{}}}$", EntityId<FmtExtender>::LENGTH);
}
struct MemberIdFormatter
{
static std::string format(const std::string& core)
{
return fmt::format("m[{}]", core);
}
static constexpr auto ID_LABEL = "MemberId";
};
using MemberId = EntityId<MemberIdFormatter>;
struct UserIdFormatter
{
static std::string format(const std::string& core)
{
return fmt::format("u[{}]", core);
}
static constexpr auto ID_LABEL = "UserId";
};
using UserId = EntityId<UserIdFormatter>;
struct NodeIdFormatter
{
static std::string format(const std::string& core)
{
return fmt::format("n[{}]", core);
}
static constexpr auto ID_LABEL = "NodeId";
};
using NodeId = EntityId<NodeIdFormatter>;
}
namespace std
{
template <typename FmtExtender>
static inline std::ostream& operator<<(
std::ostream& os, const ccf::EntityId<FmtExtender>& entity_id)
{
if constexpr (std::is_same_v<FmtExtender, void>)
{
os << entity_id.value();
}
else
{
os << FmtExtender::format(entity_id.value());
}
return os;
}
template <typename FmtExtender>
struct hash<ccf::EntityId<FmtExtender>>
{
size_t operator()(const ccf::EntityId<FmtExtender>& entity_id) const
{
return std::hash<std::string>{}(entity_id.value());
}
};
}
FMT_BEGIN_NAMESPACE
template <typename FmtExtender>
struct formatter<ccf::EntityId<FmtExtender>>
{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const ccf::EntityId<FmtExtender>& v, FormatContext& ctx) const
{
std::stringstream ss;
ss << v;
return format_to(ctx.out(), "{}", ss.str());
}
};
FMT_END_NAMESPACE
namespace ccf::kv::serialisers
{
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()));
}
};
}