♻️ 使用module重构所有代码
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
module;
|
||||
|
||||
export module lsp.codec.common;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.protocol.common.basic_types;
|
||||
|
||||
export namespace lsp::codec
|
||||
{
|
||||
/// 转换错误异常类
|
||||
class ConversionError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit ConversionError(const std::string& message) : std::runtime_error("LSP Conversion Error: " + message) {}
|
||||
};
|
||||
|
||||
/// 类型特征:LSP 基本类型判断
|
||||
template<typename T>
|
||||
inline constexpr bool is_lsp_basic_type_v =
|
||||
std::is_same_v<T, protocol::integer> ||
|
||||
std::is_same_v<T, protocol::uinteger> ||
|
||||
std::is_same_v<T, protocol::decimal> ||
|
||||
std::is_same_v<T, protocol::boolean> ||
|
||||
std::is_same_v<T, protocol::string> ||
|
||||
std::is_same_v<T, std::nullptr_t>;
|
||||
|
||||
/// 类型特征:LSP 容器类型判断
|
||||
template<typename T>
|
||||
inline constexpr bool is_lsp_container_type_v =
|
||||
std::is_same_v<T, protocol::LSPObject> ||
|
||||
std::is_same_v<T, protocol::LSPArray> ||
|
||||
std::is_same_v<T, protocol::LSPAny>;
|
||||
|
||||
/// 类型特征:检测 vector
|
||||
template<typename T>
|
||||
struct is_vector : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_vector<std::vector<T>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_vector_v = is_vector<T>::value;
|
||||
|
||||
/// 类型特征:检测 map
|
||||
template<typename T>
|
||||
struct is_map : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename K, typename V>
|
||||
struct is_map<std::map<K, V>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_map_v = is_map<T>::value;
|
||||
|
||||
/// 类型特征:检测 optional
|
||||
template<typename T>
|
||||
struct is_optional : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_optional<std::optional<T>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_optional_v = is_optional<T>::value;
|
||||
|
||||
/// 类型特征:检测 variant
|
||||
template<typename T>
|
||||
struct is_variant : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct is_variant<std::variant<Ts...>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_variant_v = is_variant<T>::value;
|
||||
|
||||
/// 类型特征:用户自定义 struct 判断
|
||||
template<typename T>
|
||||
inline constexpr bool is_user_struct_v =
|
||||
std::is_class_v<T> &&
|
||||
!std::is_pointer_v<T> &&
|
||||
!std::is_same_v<T, protocol::string> &&
|
||||
!std::is_same_v<T, std::string> &&
|
||||
!is_lsp_basic_type_v<T> &&
|
||||
!is_lsp_container_type_v<T> &&
|
||||
!is_vector_v<T> &&
|
||||
!is_map_v<T> &&
|
||||
!is_optional_v<T> &&
|
||||
!is_variant_v<T>;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
module;
|
||||
|
||||
import glaze;
|
||||
|
||||
export module lsp.codec.facade;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.codec.transformer;
|
||||
import lsp.protocol.common.basic_types;
|
||||
|
||||
export namespace lsp::codec
|
||||
{
|
||||
template<typename T>
|
||||
std::optional<T> Deserialize(const std::string& json);
|
||||
|
||||
template<typename T>
|
||||
std::optional<std::string> Serialize(const T& obj);
|
||||
|
||||
inline constexpr auto ToLSPAny = [](const auto& value) {
|
||||
return LSPAnyConverter::ToLSPAny(value);
|
||||
};
|
||||
|
||||
inline constexpr auto FromLSPAny = []<typename T>(const auto& input) -> T {
|
||||
using InputType = std::decay_t<decltype(input)>;
|
||||
|
||||
protocol::LSPAny any;
|
||||
|
||||
if constexpr (std::is_same_v<InputType, std::variant<protocol::LSPArray, protocol::LSPObject>>)
|
||||
any = std::visit([](const auto& v) -> protocol::LSPAny { return v; }, input);
|
||||
else
|
||||
any = input;
|
||||
|
||||
return LSPAnyConverter::FromLSPAny<T>(any);
|
||||
};
|
||||
|
||||
namespace check
|
||||
{
|
||||
bool IsObject(const protocol::LSPAny& any);
|
||||
bool IsArray(const protocol::LSPAny& any);
|
||||
bool IsString(const protocol::LSPAny& any);
|
||||
bool IsNumber(const protocol::LSPAny& any);
|
||||
bool IsBool(const protocol::LSPAny& any);
|
||||
bool IsNull(const protocol::LSPAny& any);
|
||||
}
|
||||
|
||||
namespace debug
|
||||
{
|
||||
std::string GetTypeName(const protocol::LSPAny& any);
|
||||
std::string GetIdString(const std::variant<int, std::string>& id);
|
||||
}
|
||||
}
|
||||
|
||||
namespace lsp::codec
|
||||
{
|
||||
// ==================== JSON 序列化/反序列化 ====================
|
||||
template<typename T>
|
||||
std::optional<T> Deserialize(const std::string& json)
|
||||
{
|
||||
T obj;
|
||||
auto ce = glz::read_json(obj, json);
|
||||
if (ce)
|
||||
return std::nullopt;
|
||||
else
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<std::string> Serialize(const T& obj)
|
||||
{
|
||||
std::string json;
|
||||
auto ce = glz::write_json(obj, json);
|
||||
if (ce)
|
||||
return std::nullopt;
|
||||
else
|
||||
return json;
|
||||
}
|
||||
|
||||
// ==================== 类型检查 ====================
|
||||
namespace check
|
||||
{
|
||||
inline bool IsObject(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<protocol::LSPObject>();
|
||||
}
|
||||
|
||||
inline bool IsArray(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<protocol::LSPArray>();
|
||||
}
|
||||
|
||||
inline bool IsString(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<protocol::string>();
|
||||
}
|
||||
|
||||
inline bool IsNumber(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<protocol::integer>() || any.Is<protocol::uinteger>() || any.Is<protocol::decimal>();
|
||||
}
|
||||
|
||||
inline bool IsBool(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<protocol::boolean>();
|
||||
}
|
||||
|
||||
inline bool IsNull(const protocol::LSPAny& any)
|
||||
{
|
||||
return any.Is<std::nullptr_t>();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 调试工具 ====================
|
||||
namespace debug
|
||||
{
|
||||
inline std::string GetTypeName(const protocol::LSPAny& any)
|
||||
{
|
||||
if (any.Is<protocol::LSPObject>())
|
||||
return "LSPObject";
|
||||
if (any.Is<protocol::LSPArray>())
|
||||
return "LSPArray";
|
||||
if (any.Is<protocol::string>())
|
||||
return "string";
|
||||
if (any.Is<protocol::integer>())
|
||||
return "integer";
|
||||
if (any.Is<protocol::uinteger>())
|
||||
return "uinteger";
|
||||
if (any.Is<protocol::decimal>())
|
||||
return "decimal";
|
||||
if (any.Is<protocol::boolean>())
|
||||
return "boolean";
|
||||
if (any.Is<std::nullptr_t>())
|
||||
return "null";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
inline std::string GetIdString(const std::variant<int, std::string>& id)
|
||||
{
|
||||
return std::visit([](const auto& value) -> std::string {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, int>)
|
||||
return std::to_string(value);
|
||||
else
|
||||
return value;
|
||||
},
|
||||
id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
module;
|
||||
|
||||
import glaze;
|
||||
|
||||
export module lsp.codec.transformer;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.codec.common;
|
||||
import lsp.protocol.common.basic_types;
|
||||
|
||||
export namespace lsp::codec
|
||||
{
|
||||
class LSPAnyConverter
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static protocol::LSPAny ToLSPAny(const T& value);
|
||||
|
||||
template<typename T>
|
||||
static T FromLSPAny(const protocol::LSPAny& any);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static T ExtractNumber(const protocol::LSPAny& any);
|
||||
|
||||
template<typename T>
|
||||
static T ConvertViaJson(const protocol::LSPAny& any);
|
||||
|
||||
template<typename T>
|
||||
static protocol::LSPAny SerializeViaJson(const T& obj);
|
||||
};
|
||||
}
|
||||
|
||||
// ==================== 实现 ====================
|
||||
namespace lsp::codec
|
||||
{
|
||||
template<typename T>
|
||||
protocol::LSPAny LSPAnyConverter::ToLSPAny(const T& value)
|
||||
{
|
||||
using Type = std::decay_t<T>;
|
||||
|
||||
if constexpr (std::is_same_v<Type, protocol::LSPAny>)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, protocol::LSPObject>)
|
||||
{
|
||||
return protocol::LSPAny(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, protocol::LSPArray>)
|
||||
{
|
||||
return protocol::LSPAny(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, const char*> || std::is_same_v<Type, char*>)
|
||||
{
|
||||
return protocol::LSPAny(protocol::string(value));
|
||||
}
|
||||
else if constexpr (is_lsp_basic_type_v<Type>)
|
||||
{
|
||||
return protocol::LSPAny(value);
|
||||
}
|
||||
else if constexpr (std::is_integral_v<Type> && !std::is_same_v<Type, bool>)
|
||||
{
|
||||
return protocol::LSPAny(value);
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<Type>)
|
||||
{
|
||||
return protocol::LSPAny(value);
|
||||
}
|
||||
else if constexpr (is_vector_v<Type>)
|
||||
{
|
||||
protocol::LSPArray arr;
|
||||
arr.reserve(value.size());
|
||||
for (const auto& item : value)
|
||||
arr.push_back(ToLSPAny(item));
|
||||
return protocol::LSPAny(std::move(arr));
|
||||
}
|
||||
else if constexpr (is_map_v<Type>)
|
||||
{
|
||||
protocol::LSPObject obj;
|
||||
for (const auto& [key, val] : value)
|
||||
obj[key] = ToLSPAny(val);
|
||||
return protocol::LSPAny(std::move(obj));
|
||||
}
|
||||
else if constexpr (is_optional_v<Type>)
|
||||
{
|
||||
if (value.has_value())
|
||||
return ToLSPAny(*value);
|
||||
return protocol::LSPAny(nullptr);
|
||||
}
|
||||
else if constexpr (is_user_struct_v<Type>)
|
||||
{
|
||||
return SerializeViaJson(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(!sizeof(Type), "Unsupported type for ToLSPAny");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LSPAnyConverter::FromLSPAny(const protocol::LSPAny& any)
|
||||
{
|
||||
using Type = std::decay_t<T>;
|
||||
|
||||
if constexpr (std::is_same_v<Type, protocol::LSPAny>)
|
||||
{
|
||||
return any;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, protocol::LSPObject>)
|
||||
{
|
||||
if (!any.Is<protocol::LSPObject>())
|
||||
throw ConversionError("LSPAny does not contain LSPObject");
|
||||
return any.Get<protocol::LSPObject>();
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, protocol::LSPArray>)
|
||||
{
|
||||
if (!any.Is<protocol::LSPArray>())
|
||||
throw ConversionError("LSPAny does not contain LSPArray");
|
||||
return any.Get<protocol::LSPArray>();
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, bool>)
|
||||
{
|
||||
if (!any.Is<protocol::boolean>())
|
||||
throw ConversionError("LSPAny does not contain a boolean");
|
||||
return any.Get<protocol::boolean>();
|
||||
}
|
||||
else if constexpr (std::is_same_v<Type, protocol::string> || std::is_same_v<Type, std::string>)
|
||||
{
|
||||
if (!any.Is<protocol::string>())
|
||||
throw ConversionError("LSPAny does not contain a string");
|
||||
return any.Get<protocol::string>();
|
||||
}
|
||||
else if constexpr (std::is_arithmetic_v<Type> && !std::is_same_v<Type, bool>)
|
||||
{
|
||||
return ExtractNumber<Type>(any);
|
||||
}
|
||||
else if constexpr (is_vector_v<Type>)
|
||||
{
|
||||
if (!any.Is<protocol::LSPArray>())
|
||||
throw ConversionError("LSPAny does not contain an array");
|
||||
|
||||
const auto& arr = any.Get<protocol::LSPArray>();
|
||||
Type result;
|
||||
result.reserve(arr.size());
|
||||
for (const auto& item : arr)
|
||||
result.push_back(FromLSPAny<typename Type::value_type>(item));
|
||||
return result;
|
||||
}
|
||||
else if constexpr (is_map_v<Type>)
|
||||
{
|
||||
if (!any.Is<protocol::LSPObject>())
|
||||
throw ConversionError("LSPAny does not contain an object");
|
||||
|
||||
const auto& obj = any.Get<protocol::LSPObject>();
|
||||
Type result;
|
||||
for (const auto& [key, val] : obj)
|
||||
result[key] = FromLSPAny<typename Type::mapped_type>(val);
|
||||
return result;
|
||||
}
|
||||
else if constexpr (is_optional_v<Type>)
|
||||
{
|
||||
if (any.Is<std::nullptr_t>())
|
||||
return std::nullopt;
|
||||
return FromLSPAny<typename Type::value_type>(any);
|
||||
}
|
||||
else if constexpr (is_user_struct_v<Type>)
|
||||
{
|
||||
return ConvertViaJson<Type>(any);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(!sizeof(Type), "Unsupported type for FromLSPAny");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LSPAnyConverter::ExtractNumber(const protocol::LSPAny& any)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
if (any.Is<protocol::uinteger>())
|
||||
return static_cast<T>(any.Get<protocol::uinteger>());
|
||||
if (any.Is<protocol::integer>())
|
||||
return static_cast<T>(any.Get<protocol::integer>());
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<T>)
|
||||
{
|
||||
if (any.Is<protocol::decimal>())
|
||||
return static_cast<T>(any.Get<protocol::decimal>());
|
||||
}
|
||||
|
||||
throw ConversionError("LSPAny does not contain a compatible numeric type");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LSPAnyConverter::ConvertViaJson(const protocol::LSPAny& any)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (any.Is<std::nullptr_t>())
|
||||
throw ConversionError("LSPAny is null; cannot convert to target type");
|
||||
|
||||
std::string json;
|
||||
auto ec = glz::write_json(any, json);
|
||||
if (ec)
|
||||
throw ConversionError("Failed to serialize LSPAny to JSON: " + std::string(glz::format_error(ec, json)));
|
||||
|
||||
T obj;
|
||||
ec = glz::read_json(obj, json);
|
||||
if (ec)
|
||||
throw ConversionError("Failed to parse JSON to target type: " + std::string(glz::format_error(ec, json)));
|
||||
|
||||
return obj;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw ConversionError("LSPAny to struct conversion failed: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
protocol::LSPAny LSPAnyConverter::SerializeViaJson(const T& obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string json;
|
||||
auto ec = glz::write_json(obj, json);
|
||||
if (ec)
|
||||
throw ConversionError("Failed to serialize struct to JSON: " + std::string(glz::format_error(ec, json)));
|
||||
|
||||
protocol::LSPAny any;
|
||||
ec = glz::read_json(any, json);
|
||||
if (ec)
|
||||
throw ConversionError("Failed to parse JSON to LSPAny: " + std::string(glz::format_error(ec, json)));
|
||||
|
||||
return any;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw ConversionError("struct to LSPAny conversion failed: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user