| name | meojson |
| description | Guide for using the meojson C++ JSON library in MaaFramework. Use when writing code that involves JSON parsing, serialization, struct jsonization (MEO_JSONIZATION), json::value manipulation, ext::jsonization custom type support, or logging with json values. |
meojson in MaaFramework
meojson is a header-only, zero-dependency C++ JSON library. In MaaFramework it lives at source/MaaUtils/include/meojson/ and is included 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>
auto opt = json::parse(str);
if (!opt) { }
auto opt = json::open("/path/to/file.json");
auto opt = json::parsec(str);
auto opt = json::parse(istream, false, false);
MaaFramework pattern — always check parse result and type:
auto ov_opt = json::parse(pipeline_override);
if (!ov_opt) {
LogError << "failed to parse" << VAR(pipeline_override);
return MaaInvalidId;
}
if (!ov_opt->is_object()) {
LogError << "json is not object" << VAR(pipeline_override);
return MaaInvalidId;
}
auto& obj = ov_opt->as_object();
Constructing Values
json::value v1 = 42;
json::value v2 = "hello";
json::value v3 = true;
json::value v4 = nullptr;
json::array arr { 1, 2, "three" };
json::object obj {
{ "key1", "value1" },
{ "key2", 42 },
};
std::vector<int> vec = {1, 2, 3};
json::value v5 = vec;
std::map<std::string, int> m = {{"a", 1}};
json::value v6 = m;
json::value v7 = { {"name", "test"}, {"count", 5} };
Reading Values
Type Checking
v.valid()
v.is_null()
v.is_boolean()
v.is_number()
v.is_string()
v.is_array()
v.is_object()
v.is<int>()
Direct Access (throws on type mismatch)
v.as_string()
v.as_string_view()
v.as_integer()
v.as_double()
v.as_boolean()
v.as_array()
v.as_object()
v.as<T>()
Safe Access
auto opt = v.find<std::string>("key");
if (opt) {
std::string s = *opt;
}
std::string s = v.get("key", "default_value");
int n = v.get("a", "b", 0);
if (v.exists("key")) { ... }
MaaFramework pattern — find + type check:
template <typename OutT>
bool get_and_check_value(const json::value& input, const std::string& key, OutT& output, const OutT& default_val)
{
auto opt = input.find<OutT>(key);
if (!opt) {
if (input.exists(key)) {
LogError << "type error" << VAR(key) << VAR(input);
return false;
}
output = default_val;
}
else {
output = *opt;
}
return true;
}
Subscript Access
const json::value& v2 = v["key"];
const json::value& v3 = v[0];
v["key"] = "new_value";
Iteration
for (const auto& item : v.as_array()) { ... }
for (const auto& [key, val] : v.as_object()) { ... }
Serialization
v.dumps()
v.dumps(4)
v.format()
v.to_string()
Object Merge Operator
json::value merged = obj1 | obj2;
obj1 |= obj2;
MEO_JSONIZATION — Struct ↔ JSON
The macro MEO_JSONIZATION(fields...) generates to_json(), check_json(), from_json() member functions for a struct.
Basic Usage
struct MyData {
std::string name;
int count = 0;
std::vector<int> items;
MEO_JSONIZATION(name, count, items);
};
MyData data { "test", 42, {1, 2, 3} };
json::value j = data;
json::value j2 = json::parse(str).value();
MyData data2 = j2.as<MyData>();
MEO_OPT — Optional Fields
By default all fields are required in from_json(). Prefix with MEO_OPT to make a field optional (keeps default value if missing):
struct Config {
std::string name;
int timeout = 5000;
std::string label;
MEO_JSONIZATION(name, MEO_OPT timeout, MEO_OPT label);
};
MEO_KEY — Override JSON Key Name
When the C++ field name differs from the JSON key (e.g. reserved words), use MEO_KEY("json_key"):
struct JTemplateMatch {
std::vector<std::string> template_;
MEO_TOJSON(MEO_KEY("template") template_);
};
Combine with MEO_OPT:
MEO_JSONIZATION(MEO_OPT MEO_KEY("default") default_);
MEO_TOJSON / MEO_FROMJSON / MEO_CHECKJSON
These are sub-macros if you only need one direction:
| Macro | Generates |
|---|
MEO_TOJSON(...) | to_json() only |
MEO_FROMJSON(...) | from_json() only |
MEO_CHECKJSON(...) | check_json() only |
MEO_JSONIZATION(...) | All three |
In MaaFramework, PipelineTypesV2.h (dump-only structs) uses MEO_TOJSON exclusively.
Supported Field Types
MEO_JSONIZATION supports any type that json::value can convert to/from:
- 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()
- Types with
ext::jsonization<T> specialization
json::value, json::object, json::array directly
ext::jsonization — Custom Type Support
For types you don't own (or need special conversion logic), 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;
}
};
}
MaaFramework defines these in MaaUtils/JsonExt.hpp:
std::wstring ↔ UTF-8 string
std::filesystem::path ↔ UTF-8 string
std::chrono::milliseconds → "123ms" string (to_json only)
cv::Point ↔ [x, y]
cv::Rect ↔ [x, y, w, h]
cv::Size ↔ [w, h]
cv::Mat → [rows, cols, type] (to_json only)
- Fallback for any type with
operator<< → string
Logging Integration
MaaFramework's LogStream converts any value to JSON for logging via json::value constructor:
json::value j(std::forward<T>(value));
buffer_ << (j.is_string() ? j.as_string() : j.dumps()) << sep.str;
This means you can log any type that json::value can construct from (including structs with MEO_JSONIZATION or ext::jsonization):
cv::Rect rect(10, 20, 100, 200);
LogInfo << "rect:" << rect;
MyData data { "test", 42 };
LogDebug << VAR(data);
Strings are logged without quotes; other types are logged as dumps() output.
Enum Reflection
meojson supports automatic enum ↔ string conversion. Use MEOJSON_ENUM_RANGE in the enum:
enum class MyEnum {
A,
B,
C,
MEOJSON_ENUM_RANGE(A, C)
};
json::value j = MyEnum::B;
MyEnum e = j.as<MyEnum>();
Common Pitfalls
json::parse returns std::optional — always check before use
as_*() throws on type mismatch — use find() or check is_*() first
char is deleted — json::value('a') won't compile; use std::string or int
ext::jsonization lives in json::ext namespace — don't forget the namespace
MEO_OPT applies to the next field only — each optional field needs its own MEO_OPT
MEO_KEY goes after MEO_OPT — order is MEO_OPT MEO_KEY("key") field
- Object merge
| creates new value — use |= for in-place merge
std::variant serialization — converts to/from the first matching alternative
Quick Reference
For detailed API signatures and template constraints, see reference.md.