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 static protocol::LSPAny ToLSPAny(const T& value); template static T FromLSPAny(const protocol::LSPAny& any); private: template static T ExtractNumber(const protocol::LSPAny& any); template static T ConvertViaJson(const protocol::LSPAny& any); template static protocol::LSPAny SerializeViaJson(const T& obj); }; } // ==================== 实现 ==================== namespace lsp::codec { template protocol::LSPAny LSPAnyConverter::ToLSPAny(const T& value) { using Type = std::decay_t; if constexpr (std::is_same_v) { return value; } else if constexpr (std::is_same_v) { return protocol::LSPAny(value); } else if constexpr (std::is_same_v) { return protocol::LSPAny(value); } else if constexpr (std::is_same_v || std::is_same_v) { return protocol::LSPAny(protocol::string(value)); } else if constexpr (is_lsp_basic_type_v) { return protocol::LSPAny(value); } else if constexpr (std::is_integral_v && !std::is_same_v) { return protocol::LSPAny(value); } else if constexpr (std::is_floating_point_v) { return protocol::LSPAny(value); } else if constexpr (is_vector_v) { 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) { 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) { if (value.has_value()) return ToLSPAny(*value); return protocol::LSPAny(nullptr); } else if constexpr (is_user_struct_v) { return SerializeViaJson(value); } else { static_assert(!sizeof(Type), "Unsupported type for ToLSPAny"); } } template T LSPAnyConverter::FromLSPAny(const protocol::LSPAny& any) { using Type = std::decay_t; if constexpr (std::is_same_v) { return any; } else if constexpr (std::is_same_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain LSPObject"); return any.Get(); } else if constexpr (std::is_same_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain LSPArray"); return any.Get(); } else if constexpr (std::is_same_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain a boolean"); return any.Get(); } else if constexpr (std::is_same_v || std::is_same_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain a string"); return any.Get(); } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { return ExtractNumber(any); } else if constexpr (is_vector_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain an array"); const auto& arr = any.Get(); Type result; result.reserve(arr.size()); for (const auto& item : arr) result.push_back(FromLSPAny(item)); return result; } else if constexpr (is_map_v) { if (!any.Is()) throw ConversionError("LSPAny does not contain an object"); const auto& obj = any.Get(); Type result; for (const auto& [key, val] : obj) result[key] = FromLSPAny(val); return result; } else if constexpr (is_optional_v) { if (any.Is()) return std::nullopt; return FromLSPAny(any); } else if constexpr (is_user_struct_v) { return ConvertViaJson(any); } else { static_assert(!sizeof(Type), "Unsupported type for FromLSPAny"); } } template T LSPAnyConverter::ExtractNumber(const protocol::LSPAny& any) { if constexpr (std::is_integral_v) { if (any.Is()) return static_cast(any.Get()); if (any.Is()) return static_cast(any.Get()); } else if constexpr (std::is_floating_point_v) { if (any.Is()) return static_cast(any.Get()); if (any.Is()) return static_cast(any.Get()); if (any.Is()) return static_cast(any.Get()); } throw ConversionError("LSPAny does not contain a compatible numeric type"); } template T LSPAnyConverter::ConvertViaJson(const protocol::LSPAny& any) { try { if (any.Is()) 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 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())); } } }