tsl-devkit/lsp-server/test/test_glaz/test_lspany.cpp

849 lines
19 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.

#include <glaze/glaze.hpp>
#include <variant>
#include <map>
#include <vector>
#include <string>
#include <cstdint>
#include <optional>
#include <type_traits>
using integer = std::int32_t;
using uinteger = std::uint32_t;
using decimal = double;
using boolean = bool;
using string = std::string;
// 前向声明
struct LSPAny;
using LSPObject = std::map<string, LSPAny>;
using LSPArray = std::vector<LSPAny>;
using LSPAnyVariant = std::variant<
LSPObject,
LSPArray,
string,
decimal, // 放在前面,优先匹配数字
boolean,
std::nullptr_t>;
struct LSPAny
{
LSPAnyVariant value;
// 默认构造函数
LSPAny() :
value(nullptr) {}
// 拷贝和移动构造函数
LSPAny(const LSPAny& other) :
value(other.value) {}
LSPAny(LSPAny&& other) noexcept :
value(std::move(other.value)) {}
// 针对每种支持的类型的构造函数
LSPAny(const std::map<string, LSPAny>& val) :
value(val) {}
LSPAny(std::map<string, LSPAny>&& val) :
value(std::move(val)) {}
LSPAny(const std::vector<LSPAny>& val) :
value(val) {}
LSPAny(std::vector<LSPAny>&& val) :
value(std::move(val)) {}
LSPAny(const string& val) :
value(val) {}
LSPAny(string&& val) :
value(std::move(val)) {}
LSPAny(const char* val) :
value(string(val)) {}
// 所有数字类型都转换为 decimal
LSPAny(int val) :
value(static_cast<decimal>(val)) {}
LSPAny(long val) :
value(static_cast<decimal>(val)) {}
LSPAny(long long val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned int val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned long val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned long long val) :
value(static_cast<decimal>(val)) {}
LSPAny(float val) :
value(static_cast<decimal>(val)) {}
LSPAny(double val) :
value(val) {}
LSPAny(long double val) :
value(static_cast<decimal>(val)) {}
LSPAny(boolean val) :
value(val) {}
LSPAny(std::nullptr_t) :
value(nullptr) {}
// 赋值操作符
LSPAny& operator=(const LSPAny& other)
{
value = other.value;
return *this;
}
LSPAny& operator=(LSPAny&& other) noexcept
{
value = std::move(other.value);
return *this;
}
// 针对每种支持的类型的赋值操作符
LSPAny& operator=(const std::map<string, LSPAny>& val)
{
value = val;
return *this;
}
LSPAny& operator=(std::map<string, LSPAny>&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const std::vector<LSPAny>& val)
{
value = val;
return *this;
}
LSPAny& operator=(std::vector<LSPAny>&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const string& val)
{
value = val;
return *this;
}
LSPAny& operator=(string&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const char* val)
{
value = string(val);
return *this;
}
// 所有数字类型都转换为 decimal
LSPAny& operator=(int val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned int val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(float val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(double val)
{
value = val;
return *this;
}
LSPAny& operator=(long double val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(boolean val)
{
value = val;
return *this;
}
LSPAny& operator=(std::nullptr_t)
{
value = nullptr;
return *this;
}
// 类型检查辅助函数
template<typename T>
bool is() const
{
return std::holds_alternative<T>(value);
}
template<typename T>
T& get()
{
return std::get<T>(value);
}
template<typename T>
const T& get() const
{
return std::get<T>(value);
}
// 访问操作符
template<typename Visitor>
auto visit(Visitor&& visitor) const
{
return std::visit(std::forward<Visitor>(visitor), value);
}
template<typename Visitor>
auto visit(Visitor&& visitor)
{
return std::visit(std::forward<Visitor>(visitor), value);
}
};
// glaze 自动支持 std::variant无需额外配置
namespace glz
{
template<>
struct meta<LSPAny>
{
using T = LSPAny;
static constexpr auto value = &T::value;
};
}
// ===== 简单清晰的转换模板 =====
// 转换工具类
struct LSPConvert
{
// === 基本类型的转换(优先级最高) ===
// boolean
static LSPAny ToLSPAny(boolean value)
{
return LSPAny(value);
}
// 整数类型
static LSPAny ToLSPAny(int value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned int value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long long value)
{
return LSPAny(value);
}
// 浮点类型
static LSPAny ToLSPAny(float value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(double value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long double value)
{
return LSPAny(value);
}
// string
static LSPAny ToLSPAny(const string& str)
{
return LSPAny(str);
}
static LSPAny ToLSPAny(const char* str)
{
return LSPAny(str);
}
// nullptr
static LSPAny ToLSPAny(std::nullptr_t)
{
return LSPAny(nullptr);
}
// LSPAny 自身
static LSPAny ToLSPAny(const LSPAny& any)
{
return any;
}
// === 容器类型的转换 ===
// vector
template<typename T>
static LSPAny ToLSPAny(const std::vector<T>& vec)
{
LSPArray arr;
arr.reserve(vec.size());
for (const auto& item : vec)
{
arr.push_back(ToLSPAny(item));
}
return LSPAny(std::move(arr));
}
// map
template<typename T>
static LSPAny ToLSPAny(const std::map<string, T>& map)
{
LSPObject obj;
for (const auto& [key, value] : map)
{
obj[key] = ToLSPAny(value);
}
return LSPAny(std::move(obj));
}
// optional
template<typename T>
static LSPAny ToLSPAny(const std::optional<T>& opt)
{
if (opt.has_value())
{
return ToLSPAny(*opt);
}
return LSPAny(nullptr);
}
// === Struct 到 LSPAny 的转换(最低优先级) ===
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny>::type
ToLSPAny(const T& obj)
{
// 序列化为 JSON 字符串
std::string json;
auto ec = glz::write_json(obj, json);
if (ec)
{
throw std::runtime_error("Failed to serialize to JSON");
}
// 直接解析为 LSPAny
LSPAny result;
ec = glz::read_json(result, json);
if (ec)
{
throw std::runtime_error("Failed to parse JSON to LSPAny");
}
return result;
}
// === LSPAny 到基本类型的转换 ===
// boolean
static boolean BoolFromLSPAny(const LSPAny& any)
{
if (!any.is<boolean>())
{
throw std::runtime_error("LSPAny is not a boolean");
}
return any.get<boolean>();
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
NumberFromLSPAny(const LSPAny& any)
{
if (!any.is<decimal>())
{
throw std::runtime_error("LSPAny is not a number");
}
return static_cast<T>(any.get<decimal>());
}
// string
static string StringFromLSPAny(const LSPAny& any)
{
if (!any.is<string>())
{
throw std::runtime_error("LSPAny is not a string");
}
return any.get<string>();
}
// === LSPAny 到容器类型的转换 ===
// vector
template<typename T>
static std::vector<T> VectorFromLSPAny(const LSPAny& any)
{
if (!any.is<LSPArray>())
{
throw std::runtime_error("LSPAny is not an array");
}
const auto& arr = any.get<LSPArray>();
std::vector<T> result;
result.reserve(arr.size());
for (const auto& item : arr)
{
result.push_back(FromLSPAny<T>(item));
}
return result;
}
// optional
template<typename T>
static std::optional<T> OptionalFromLSPAny(const LSPAny& any)
{
if (any.is<std::nullptr_t>())
{
return std::nullopt;
}
return FromLSPAny<T>(any);
}
// === LSPAny 到 Struct 的转换 ===
template<typename T>
static T FromLSPAny(const LSPAny& any)
{
return FromLSPAnyImpl<T>(any);
}
private:
// 内部实现,使用重载来处理不同类型
// boolean
static boolean FromLSPAnyImpl(const LSPAny& any, boolean*)
{
return BoolFromLSPAny(any);
}
// string
static string FromLSPAnyImpl(const LSPAny& any, string*)
{
return StringFromLSPAny(any);
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
FromLSPAnyImpl(const LSPAny& any, T*)
{
return NumberFromLSPAny<T>(any);
}
// LSPAny 自身
static LSPAny FromLSPAnyImpl(const LSPAny& any, LSPAny*)
{
return any;
}
// struct 类型
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, LSPAny>::value,
T>::type
FromLSPAnyImpl(const LSPAny& any, T*)
{
// 序列化 LSPAny 为 JSON
std::string json;
auto ec = glz::write_json(any.value, json);
if (ec)
{
throw std::runtime_error("Failed to serialize LSPAny to JSON");
}
// 解析 JSON 到目标类型
T result;
ec = glz::read_json(result, json);
if (ec)
{
throw std::runtime_error("Failed to parse JSON to target type");
}
return result;
}
// 通过指针类型来分派
template<typename T>
static T FromLSPAnyImpl(const LSPAny& any)
{
return FromLSPAnyImpl(any, static_cast<T*>(nullptr));
}
};
// ===== 便利函数(可选) =====
// 基本类型的便利函数
inline LSPAny ToLSPAny(boolean value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(float value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(const string& str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(const char* str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(std::nullptr_t) { return LSPConvert::ToLSPAny(nullptr); }
inline LSPAny ToLSPAny(const LSPAny& any) { return LSPConvert::ToLSPAny(any); }
// 容器类型的便利函数
template<typename T>
LSPAny ToLSPAny(const std::vector<T>& vec)
{
return LSPConvert::ToLSPAny(vec);
}
template<typename T>
LSPAny ToLSPAny(const std::map<string, T>& map)
{
return LSPConvert::ToLSPAny(map);
}
template<typename T>
LSPAny ToLSPAny(const std::optional<T>& opt)
{
return LSPConvert::ToLSPAny(opt);
}
// struct 类型的便利函数
template<typename T>
typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny>::type
ToLSPAny(const T& value)
{
return LSPConvert::ToLSPAny(value);
}
// FromLSPAny 便利函数
template<typename T>
T FromLSPAny(const LSPAny& any)
{
return LSPConvert::FromLSPAny<T>(any);
}
// ===== 测试代码 =====
// 测试用的结构体
struct Message
{
string jsonrpc = "2.0";
string method;
int id = 0;
};
struct Position
{
int line;
int character;
};
struct Range
{
Position start;
Position end;
};
struct TextDocumentIdentifier
{
string uri;
};
struct TextDocumentPositionParams
{
TextDocumentIdentifier textDocument;
Position position;
};
struct CompletionItem
{
string label;
std::optional<int> kind;
std::optional<string> detail;
std::optional<string> documentation;
std::optional<boolean> deprecated;
std::optional<boolean> preselect;
std::optional<string> sortText;
std::optional<string> filterText;
std::optional<string> insertText;
};
// 为测试结构体提供 glaze 元数据
template<>
struct glz::meta<Message>
{
using T = Message;
static constexpr auto value = object(
"jsonrpc",
&T::jsonrpc,
"method",
&T::method,
"id",
&T::id);
};
template<>
struct glz::meta<Position>
{
using T = Position;
static constexpr auto value = object(
"line",
&T::line,
"character",
&T::character);
};
template<>
struct glz::meta<Range>
{
using T = Range;
static constexpr auto value = object(
"start",
&T::start,
"end",
&T::end);
};
template<>
struct glz::meta<TextDocumentIdentifier>
{
using T = TextDocumentIdentifier;
static constexpr auto value = object(
"uri",
&T::uri);
};
template<>
struct glz::meta<TextDocumentPositionParams>
{
using T = TextDocumentPositionParams;
static constexpr auto value = object(
"textDocument",
&T::textDocument,
"position",
&T::position);
};
template<>
struct glz::meta<CompletionItem>
{
using T = CompletionItem;
static constexpr auto value = object(
"label",
&T::label,
"kind",
&T::kind,
"detail",
&T::detail,
"documentation",
&T::documentation,
"deprecated",
&T::deprecated,
"preselect",
&T::preselect,
"sortText",
&T::sortText,
"filterText",
&T::filterText,
"insertText",
&T::insertText);
};
// 测试函数
#include <iostream>
void test_basic_conversion()
{
std::cout << "=== Testing Basic Conversion ===" << std::endl;
// 测试 struct 转换
Message msg;
msg.method = "textDocument/completion";
msg.id = 42;
// Struct -> LSPAny
LSPAny any = ToLSPAny(msg);
// 序列化查看
std::string json;
glz::write_json(any, json);
std::cout << "Message as JSON: " << json << std::endl;
// LSPAny -> Struct
Message restored = FromLSPAny<Message>(any);
std::cout << "Restored method: " << restored.method << std::endl;
std::cout << "Restored id: " << restored.id << std::endl;
}
void test_vector_conversion()
{
std::cout << "\n=== Testing Vector Conversion ===" << std::endl;
std::vector<Position> positions = {
{ 10, 5 },
{ 20, 15 },
{ 30, 25 }
};
// Vector -> LSPAny
LSPAny any = ToLSPAny(positions);
std::string json;
glz::write_json(any, json);
std::cout << "Vector as JSON: " << json << std::endl;
// LSPAny -> Vector
auto restored = LSPConvert::VectorFromLSPAny<Position>(any);
std::cout << "Restored " << restored.size() << " positions" << std::endl;
}
void test_optional_conversion()
{
std::cout << "\n=== Testing Optional Conversion ===" << std::endl;
CompletionItem item;
item.label = "std::vector";
item.kind = 1;
item.detail = "template<typename T> class vector";
LSPAny any = ToLSPAny(item);
std::string json;
glz::write_json(any, json);
std::cout << "CompletionItem as JSON: " << json << std::endl;
// 测试 null optional
std::optional<string> empty_opt;
LSPAny null_any = ToLSPAny(empty_opt);
glz::write_json(null_any, json);
std::cout << "Empty optional as JSON: " << json << std::endl;
}
void test_mixed_usage()
{
std::cout << "\n=== Testing Mixed Usage ===" << std::endl;
// 创建复杂对象
LSPObject obj;
obj["message"] = ToLSPAny(Message{ "2.0", "test/method", 123 });
obj["position"] = ToLSPAny(Position{ 10, 20 });
obj["numbers"] = ToLSPAny(std::vector<int>{ 1, 2, 3 });
obj["flag"] = LSPAny(true);
obj["value"] = LSPAny(3.14);
obj["text"] = LSPAny("Hello LSP");
obj["empty"] = LSPAny(nullptr);
LSPAny root(obj);
std::string json;
glz::write_json(root, json);
std::cout << "Complex object: " << json << std::endl;
// 提取值
if (root.is<LSPObject>())
{
auto& root_obj = root.get<LSPObject>();
Message msg = FromLSPAny<Message>(root_obj["message"]);
std::cout << "Extracted message method: " << msg.method << std::endl;
Position pos = FromLSPAny<Position>(root_obj["position"]);
std::cout << "Extracted position: " << pos.line << ", " << pos.character << std::endl;
}
}
int main()
{
try
{
test_basic_conversion();
test_vector_conversion();
test_optional_conversion();
test_mixed_usage();
std::cout << "\nAll tests completed!" << std::endl;
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}