meojson in MaaEnd cpp-algo
meojson is a header-only C++ JSON library, provided via MaaFramework deps. Include via <meojson/json.hpp>.
Core Types
| Type | Description |
|---|---|
json::value |
Universal JSON value (null/bool/number/string/array/object) |
json::array |
JSON array, wraps std::vector<json::value> |
json::object |
JSON object, wraps std::map<std::string, json::value> |
Parsing
#include <meojson/json.hpp>
// From string — returns std::optional<json::value>
auto opt = json::parse(str);
if (!opt) { /* parse failed */ }
// From file
auto opt = json::open("/path/to/file.json");
// JSONC (with comments)
auto opt = json::parsec(str);
// JSONC file: check UTF-8 BOM and allow comments
auto opt = json::open("/path/to/file.json", true, true);
json::open(path, check_bom, with_comments) 的两个布尔参数分别控制 UTF-8 BOM 检查和注释解析;默认调用 json::open(path) 是严格 JSON,既不检查 BOM,也不接受注释。
在 MaaEnd cpp-algo 中读取仓库维护、允许注释的 JSON/JSONC 文件时,优先复用公共能力:
#include "Common/JsoncFile.h"
auto opt = common::OpenJsoncFile(path);
运行时接口参数(如 custom_recognition_param)、识别结果 detail 和生成报告仍保持严格 JSON,除非对应契约明确允许 JSONC。不要为解决仓库配置文件的注释问题而放宽运行时输入边界。
cpp-algo 推荐模式 — 安全解析自定义识别参数:
template <typename T>
T ParseCustomRecognitionParam(const char* custom_recognition_param)
{
if (!custom_recognition_param || std::strlen(custom_recognition_param) == 0) {
return T {};
}
auto opt = json::parse(custom_recognition_param);
if (!opt) {
LogError << "failed to parse custom_recognition_param" << VAR(custom_recognition_param);
return T {};
}
T result {};
if (!result.from_json(*opt)) {
LogError << "failed to deserialize param" << VAR(custom_recognition_param);
return T {};
}
return result;
}
反模式:
json::parse(str).value_or(json::object {}).as<T>()——value_or静默吞掉 parse 失败;空 object 调as<T>()当T有 required 字段时会抛异常。
Constructing Values
json::value v1 = 42;
json::value v2 = "hello";
json::value v3 = true;
json::value v4 = nullptr; // null
json::array arr { 1, 2, "three" };
json::object obj {
{ "key1", "value1" },
{ "key2", 42 },
};
// From STL containers (implicit conversion)
std::vector<int> vec = {1, 2, 3};
json::value v5 = vec; // → JSON array
std::map<std::string, int> m = {{"a", 1}};
json::value v6 = m; // → JSON object
Reading Values
Type Checking
v.is_null() / v.is_boolean() / v.is_number() / v.is_string()
v.is_array() / v.is_object()
v.is<int>() // check if convertible to type
Direct Access (throws on type mismatch)
v.as_string() // → std::string
v.as_string_view() // → std::string_view (no copy)
v.as_integer() / v.as_double() / v.as_boolean()
v.as_array() // → const json::array&
v.as_object() // → const json::object&
v.as<T>() // → T (explicit conversion)
Safe Access
// find() returns std::optional<T>
auto opt = v.find<std::string>("key");
if (opt) { std::string s = *opt; }
// get() with default value — supports chained keys
std::string s = v.get("key", "default_value");
int n = v.get("a", "b", 0); // v["a"]["b"], default 0
// exists() / contains()
if (v.exists("key")) { ... }
Subscript & Iteration
const json::value& v2 = v["key"]; // object access
v["key"] = "new_value"; // mutable (creates key if missing)
for (const auto& item : v.as_array()) { ... }
for (const auto& [key, val] : v.as_object()) { ... }
Serialization
v.dumps() // compact string
v.dumps(4) // pretty print with indent=4
v.format() // same as dumps(4)
cpp-algo 常见模式 — 写回 JSON detail:
template <typename T>
void WriteJsonDetail(MaaStringBuffer* out_detail, const T& payload)
{
if (out_detail == nullptr) return;
const std::string json_text = json::value(payload).dumps();
MaaStringBufferSet(out_detail, json_text.c_str());
}
Object Merge Operator
json::value merged = obj1 | obj2; // right side wins on conflict
obj1 |= obj2; // in-place merge
MEO_JSONIZATION — Struct ↔ JSON
MEO_JSONIZATION(fields...) generates to_json(), check_json(), from_json() member functions.
Basic Usage
struct LocateOutput {
int status = 0;
std::string message;
std::string mapName;
int x = 0;
int y = 0;
MEO_JSONIZATION(status, message, MEO_OPT mapName, MEO_OPT x, MEO_OPT y)
};
// Serialize
json::value j = data; // implicit via to_json()
// Deserialize — 安全方式:用 from_json() 检查返回值
MyData data {};
if (!data.from_json(j)) {
LogError << "failed to deserialize" << VAR(j);
}
// as<T>() 在类型不匹配 / required 字段缺失时会抛异常,仅在确定数据合法时使用
MyData data2 = j.as<MyData>();
MEO_OPT — Optional Fields
By default all fields are required in from_json(). Prefix with MEO_OPT to make optional (keeps default if missing):
struct LocateOptions {
double loc_threshold = 0.55;
double yolo_threshold = 0.70;
bool force_global_search = false;
MEO_JSONIZATION(
MEO_OPT loc_threshold,
MEO_OPT yolo_threshold,
MEO_OPT force_global_search)
};
MEO_KEY — Override JSON Key Name
struct JTemplateMatch {
std::vector<std::string> template_; // "template" is C++ keyword
MEO_TOJSON(MEO_KEY("template") template_);
};
// Combine with MEO_OPT:
MEO_JSONIZATION(MEO_OPT MEO_KEY("default") default_);
Sub-Macros
| Macro | Generates |
|---|---|
MEO_TOJSON(...) |
to_json() only |
MEO_FROMJSON(...) |
from_json() only |
MEO_CHECKJSON(...) |
check_json() only |
MEO_JSONIZATION(...) |
All three |
Supported Field Types
- Primitives:
int,double,bool,std::string - STL containers:
std::vector<T>,std::map<std::string, T>,std::array<T,N> - Nullable:
std::optional<T>,std::shared_ptr<T> - Tuple-like:
std::pair<A,B>,std::tuple<...> - Variant:
std::variant<Ts...> - Nested structs with
MEO_JSONIZATION/to_json() json::value,json::object,json::arraydirectly
ext::jsonization — Custom Type Support
For types you don't own, specialize json::ext::jsonization<T>:
namespace json::ext {
template <>
class jsonization<cv::Rect> {
public:
json::value to_json(const cv::Rect& rect) const {
return json::array { rect.x, rect.y, rect.width, rect.height };
}
bool check_json(const json::value& json) const {
return json.is<std::vector<int>>() && json.as_array().size() == 4;
}
bool from_json(const json::value& json, cv::Rect& rect) const {
auto arr = json.as<std::vector<int>>();
rect = cv::Rect(arr[0], arr[1], arr[2], arr[3]);
return true;
}
};
}
MaaUtils 已提供的特化(通过 <MaaUtils/JsonExt.hpp> 间接可用):
cv::Point↔[x, y]、cv::Rect↔[x, y, w, h]、cv::Size↔[w, h]std::filesystem::path↔ UTF-8 stringstd::chrono::milliseconds→"123ms"(to_json only)- Fallback: any type with
operator<<→ string (to_json only)
Enum Reflection
enum class MyEnum {
A, B, C,
MEOJSON_ENUM_RANGE(A, C)
};
json::value j = MyEnum::B; // → "B"
MyEnum e = j.as<MyEnum>(); // → MyEnum::B
Common Pitfalls
json::parsereturnsstd::optional— always check before use,失败路径必须LogError+ 早期returnas_*()/as<T>()throws on type mismatch — 用find()或is_*()前置检查;对 struct 用from_json()检查返回值- 禁止
.value_or(...).as<T>()— 静默吞错误 + 可能抛异常,应拆开检查(见上方推荐模式) charis deleted — usestd::stringorintext::jsonizationlives injson::extnamespaceMEO_OPTapplies to the next field only — each optional field needs its ownMEO_OPTMEO_KEYgoes afterMEO_OPT— order isMEO_OPT MEO_KEY("key") field
Quick Reference
For detailed API signatures, see reference.md.