Files
tsl-devkit/lsp-server/src/protocol/transform/transformer.inl
T
2025-11-11 18:58:21 +08:00

245 lines
8.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
namespace lsp::transform
{
// ==================== ToLSPAny 实现 ====================
template<typename T>
inline protocol::LSPAny LSPAnyConverter::ToLSPAny(const T& value)
{
using Type = std::decay_t<T>;
// LSPAny 直接返回
if constexpr (std::is_same_v<Type, protocol::LSPAny>)
{
return value;
}
// LSPObject 直接返回
else if constexpr (std::is_same_v<Type, protocol::LSPObject>)
{
return protocol::LSPAny(value);
}
// LSPArray 直接返回
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));
}
// LSP 基本类型(boolean, string, decimal, nullptr
else if constexpr (is_lsp_basic_type_v<Type>)
{
return protocol::LSPAny(value);
}
// 整数类型(依赖 LSPAny 模板构造函数)
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);
}
// vector → LSPArray
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));
}
// map → LSPObject
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));
}
// optional → LSPAny or null
else if constexpr (is_optional_v<Type>)
{
if (value.has_value())
return ToLSPAny(*value);
return protocol::LSPAny(nullptr);
}
// 用户结构体 → LSPAny (通过 JSON)
else if constexpr (is_user_struct_v<Type>)
{
return SerializeViaJson(value);
}
else
{
static_assert(!sizeof(Type), "Unsupported type for ToLSPAny");
}
}
// ==================== FromLSPAny 实现 ====================
template<typename T>
inline T LSPAnyConverter::FromLSPAny(const protocol::LSPAny& any)
{
using Type = std::decay_t<T>;
// LSPAny 直接返回
if constexpr (std::is_same_v<Type, protocol::LSPAny>)
{
return any;
}
// LSPObject 提取
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>();
}
// LSPArray 提取
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>();
}
// boolean 提取
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>();
}
// string 提取
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);
}
// vector 提取
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;
}
// map 提取
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;
}
// optional 提取
else if constexpr (is_optional_v<Type>)
{
if (any.Is<std::nullptr_t>())
return std::nullopt;
return FromLSPAny<typename Type::value_type>(any);
}
// 用户结构体提取(通过 JSON)
else if constexpr (is_user_struct_v<Type>)
{
return ConvertViaJson<Type>(any);
}
else
{
static_assert(!sizeof(Type), "Unsupported type for FromLSPAny");
}
}
// ==================== 辅助工具实现 ====================
template<typename T>
inline T LSPAnyConverter::ExtractNumber(const protocol::LSPAny& any)
{
if (any.Is<protocol::integer>())
{
return static_cast<T>(any.Get<protocol::integer>());
}
else if (any.Is<protocol::uinteger>())
{
return static_cast<T>(any.Get<protocol::uinteger>());
}
else if (any.Is<protocol::decimal>())
{
return static_cast<T>(any.Get<protocol::decimal>());
}
else
{
throw ConversionError("LSPAny does not contain a number (integer/uinteger/decimal)");
}
}
template<typename T>
inline T LSPAnyConverter::ConvertViaJson(const protocol::LSPAny& any)
{
try
{
// 序列化 LSPAny 为 JSON
std::string json;
auto ec = glz::write_json(any.value, json);
if (ec)
throw ConversionError("Failed to serialize LSPAny to JSON: " + std::string(glz::format_error(ec, json)));
// 解析 JSON 到目标类型
T result;
ec = glz::read_json(result, json);
if (ec)
throw ConversionError("Failed to parse JSON to target type: " + std::string(glz::format_error(ec, json)));
return result;
}
catch (const std::exception& e)
{
throw ConversionError("LSPAny to struct conversion failed: " + std::string(e.what()));
}
}
template<typename T>
inline protocol::LSPAny LSPAnyConverter::SerializeViaJson(const T& obj)
{
try
{
// 使用 glaze 序列化为 JSON 字符串
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)));
// 直接解析为 LSPAny
protocol::LSPAny result;
ec = glz::read_json(result, json);
if (ec)
throw ConversionError("Failed to parse JSON to LSPAny: " + std::string(glz::format_error(ec, json)));
return result;
}
catch (const std::exception& e)
{
throw ConversionError("struct to LSPAny conversion failed: " + std::string(e.what()));
}
}
}