From 70586290d3b5bf65e77c52685b32a33cea2104f1 Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Thu, 30 Jul 2026 19:20:35 -0300 Subject: [PATCH] chore(generator): retire ApiStyle::Std MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Std surface — std-typed signatures over a QVariant + LogosAPIClient body — no longer had a caller. `interface: "universal"` modules moved to `lp` (std types over the Qt-free logos-protocol C ABI), and nothing else ever selected it, so every Std branch was dead weight sitting in front of the two live ones. `--api-style=std` is now rejected with a message naming the retirement rather than aliased to `qt`. A stale caller that still passes it wants std signatures; handing it the Qt surface would fail later, further from the cause. The collapse is deliberate about the branches where Std was tested BEFORE Qt, since a naive "delete the block containing ApiStyle::Std" changes Qt output: - makeHeader's include block tested Std first, so its `else` is the Qt include list — the Qt includes are kept and promoted, not deleted. - recordToWireExpr / recordFromWireExpr returned the Qt map form from a guarded `if` and the Std form from the function's trailing `return`. The guard is dropped and the Qt form promoted to the tail; deleting only the trailing return would have left a path falling off the end. - The private-member `else if (!events.isEmpty())` arm reads as an event test but was Std-only; the Qt arm (m_eventReplica + m_eventSource) survives, so setEventSource/trigger still have their storage. - `if (apiStyle == Qt || !events.isEmpty())` is a disjunction, not an Std branch: it unwraps to an unconditional emit, keeping ensureReplica()'s declaration next to its definition. - `isRec || style == Std` loses only the right disjunct — dropping `isRec ||` would double-wrap record fields in QVariant::fromValue. mapParamTypeStd / mapReturnTypeStd / isStdRefType stay: they are the shared std type table that ApiStyle::Lp reaches through the non-Qt arm of paramTypeFor / returnTypeFor / byRefFor and directly from lpPushExpr / lpFromJsonExpr. Verified by output equivalence rather than by the build succeeding: the generator was run over 13 fixture cases (the full_api contract as both a bound interface and a baked dep, three record-bearing contracts incl. map-of-record fields, the chat module's production contract, and a no-events contract) for both qt and lp, before and after. `diff -r` over the 194 resulting files reports no differences, and the experimental --lidl backends are byte-identical too. Test suite: 180/180, unchanged. Co-Authored-By: Claude Opus 5 --- README.md | 15 +- cpp-generator/docs/project.md | 18 +- cpp-generator/docs/spec.md | 4 +- cpp-generator/legacy/generator_lib.cpp | 429 ++++++++----------------- cpp-generator/legacy/generator_lib.h | 32 +- cpp-generator/legacy/main.cpp | 32 +- tests/generator/test_records.cpp | 18 +- 7 files changed, 199 insertions(+), 349 deletions(-) diff --git a/README.md b/README.md index 4b0a331..3003cc2 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ public: LogosMap doWork(const std::string& input) { // Cross-module call through the flat LogosModules aggregator. // Because this module is `interface: "universal"`, mkLogosModule.nix - // passed -DLOGOS_API_STYLE=std to the codegen, so every + // passed -DLOGOS_API_STYLE=lp to the codegen, so every // wrapper takes/returns std types — no Qt at the call site. std::string reply = modules().some_dep.echo(input); // ... @@ -290,13 +290,18 @@ Each module's build picks **one** API style for the generated `` client | `metadata.json#interface` | `LOGOS_API_STYLE` | Wrapper signatures | |---|---|---| -| `"universal"` | `std` | `std::string`, `std::vector`, `LogosMap`, `LogosList`, `int64_t`, `StdLogosResult` | +| `"universal"` / `"cdylib"` | `lp` | `std::string`, `std::vector`, `LogosMap`, `LogosList`, `int64_t`, `StdLogosResult` | | `"legacy"` / `"provider"` / absent | `qt` (default) | `QString`, `QStringList`, `QVariantList`, `QVariantMap`, `int`, `LogosResult` | -`mkLogosModule.nix` reads `interface` and threads `-DLOGOS_API_STYLE=std` through to the codegen for universal modules; everyone else defaults to Qt and stays bit-for-bit backward compatible. Inside the universal module's `.cpp`, the call site is: +A third value, `std`, used to name a std-typed surface whose body still went +through `QVariant` + `LogosAPIClient`. It was retired once universal modules +moved to `lp`; `--api-style=std` is now rejected outright rather than aliased, +so a stale build fails loudly instead of silently getting Qt signatures. + +`mkLogosModule.nix` reads `interface` and threads `-DLOGOS_API_STYLE=lp` through to the codegen for universal modules; everyone else defaults to Qt and stays bit-for-bit backward compatible. Inside the universal module's `.cpp`, the call site is: ```cpp -// Universal module (api-style=std): +// Universal module (api-style=lp): std::string reply = modules().some_dep.echo("hi"); ``` @@ -307,7 +312,7 @@ std::string reply = modules().some_dep.echo("hi"); QString reply = modules().some_dep.echo(QString("hi")); ``` -The wire is identical (`QVariant` under the hood); for std mode the Qt↔std conversion is inlined in the generated wrapper's `.cpp`, so the calling translation unit needs zero Qt headers. +The two carry the same values; the `lp` wrapper marshals them over the logos-protocol C ABI (`lp_*`) instead of `QVariant`, so the calling translation unit needs zero Qt headers and links no qt-sdk. > **Migrating to std types**: The choice is driven entirely by `interface`. A handcrafted module that wants std types should switch to `interface: "universal"` — there's no per-flag override on `metadata.json`. diff --git a/cpp-generator/docs/project.md b/cpp-generator/docs/project.md index e2cc94d..690f09c 100644 --- a/cpp-generator/docs/project.md +++ b/cpp-generator/docs/project.md @@ -92,7 +92,9 @@ The codegen exposes **one** wrapper class per module — `` — with sig | `--api-style` | Wrapper signatures | |---|---| | `qt` (default) | `QString` / `QStringList` / `QVariantList` / `QVariantMap` / `int` / `LogosResult` | -| `std` | `std::string` / `std::vector` / `LogosMap` / `LogosList` / `int64_t` / `StdLogosResult` | +| `lp` | `std::string` / `std::vector` / `LogosMap` / `LogosList` / `int64_t` / `StdLogosResult`, over the Qt-free logos-protocol C ABI | + +(A third value, `std` — std signatures over a `QVariant` / `LogosAPIClient` body — was retired; the generator now rejects `--api-style=std` instead of aliasing it.) Both styles emit: @@ -113,15 +115,15 @@ Only the modules explicitly listed as dependencies are exposed. The runtime's `c `ApiStyle` enum + new helpers in `generator_lib`: -- `enum class ApiStyle { Qt, Std }` — passed to every wrapper-emitting function. -- File-local `mapParamTypeStd` / `mapReturnTypeStd` / `stdParamToQVariant` / `qVariantToStdReturn` — std-side type-mapping + Qt↔std conversion expressions. Hidden from `generator_lib.h` (not part of the public surface). -- `makeHeader(moduleName, className, methods, apiStyle, events)` / `makeSource(moduleName, className, headerBaseName, methods, apiStyle, events)` — single entry points that branch on `apiStyle` internally to emit the right include block, signature shape, and conversion bridges. `events` is loaded from a `.lidl` sidecar via `--events-from`; when non-empty, the wrapper also gets one typed `on(callback)` adapter per declared event (callback arg types follow `apiStyle`). The std-style wrapper grows the necessary `ensureReplica()` plumbing on demand. +- `enum class ApiStyle { Qt, Lp }` — passed to every wrapper-emitting function. +- File-local `mapParamTypeStd` / `mapReturnTypeStd` — the std-side type-mapping table the `lp` surface exposes. Hidden from `generator_lib.h` (not part of the public surface). +- `makeHeader(moduleName, className, methods, apiStyle, events)` / `makeSource(moduleName, className, headerBaseName, methods, apiStyle, events)` — single entry points that branch on `apiStyle` internally to emit the right include block, signature shape, and conversion bridges. `events` is loaded from a `.lidl` sidecar via `--events-from`; when non-empty, the wrapper also gets one typed `on(callback)` adapter per declared event (callback arg types follow `apiStyle`). Flag plumbing: -1. `metadata.json#interface == "universal"` → `mkLogosModule.nix` adds `-DLOGOS_API_STYLE=std` to `extraCmakeFlags`. Anything else (`"legacy"`, `"provider"`, absent) leaves the default `qt`. -2. `LogosModule.cmake` reads `${LOGOS_API_STYLE}` (default `qt`) and forwards `--api-style=${LOGOS_API_STYLE}` to the `logos-cpp-generator --general-only` invocation that writes the umbrella. Each module's Nix build emits **two** header derivations (`.headers-qt` and `.headers-std`) via `buildHeaders.nix` — one `logos-cpp-generator --api-style=…` run per style, at the dep's build time. A consumer's `buildPlugin.nix` picks `dep.headers-${apiStyle}` and copies its `include/` straight into the build sandbox; no codegen runs at consume time. Nix's laziness means only the variant a downstream actually depends on is realised. -3. `legacy/main.cpp` parses `--api-style` once and threads the resulting `ApiStyle` through `generateFromPlugin`, `writeUmbrellaHeader{,FromDeps}`. No `_api_std.{h,cpp}` files are ever emitted; each module gets a single `_api.h` + `_api.cpp` pair regardless of style. +1. `metadata.json#interface == "universal"` (or `"cdylib"`) → `mkLogosModule.nix` adds `-DLOGOS_API_STYLE=lp` to `extraCmakeFlags`. Anything else (`"legacy"`, `"provider"`, absent) leaves the default `qt`. +2. `LogosModule.cmake` reads `${LOGOS_API_STYLE}` (default `qt`) and forwards `--api-style=${LOGOS_API_STYLE}` to the `logos-cpp-generator --general-only` invocation that writes the umbrella. Each module's Nix build emits **two** header derivations (`.headers-qt` and `.headers-lp`) via `buildHeaders.nix` — one `logos-cpp-generator --api-style=…` run per style, at the dep's build time. A consumer's `buildPlugin.nix` picks `dep.headers-${apiStyle}` and copies its `include/` straight into the build sandbox; no codegen runs at consume time. Nix's laziness means only the variant a downstream actually depends on is realised. +3. `legacy/main.cpp` parses `--api-style` once (rejecting the retired `std`) and threads the resulting `ApiStyle` through `generateFromPlugin`, `writeUmbrellaHeader{,FromDeps}`. No per-style filenames are ever emitted; each module gets a single `_api.h` + `_api.cpp` pair regardless of style. ### Provider Generation (logos-qt-generator) @@ -191,7 +193,7 @@ The `--events-from ` flag points the legacy `.dylib --module-only` ```bash logos-cpp-generator /path/to/plugin.dylib \ - --module-only --api-style std \ + --module-only --api-style lp \ --events-from /path/to/dep/share/logos/my_module.lidl \ --output-dir ./generated ``` diff --git a/cpp-generator/docs/spec.md b/cpp-generator/docs/spec.md index b0a5e0f..c19f7e2 100644 --- a/cpp-generator/docs/spec.md +++ b/cpp-generator/docs/spec.md @@ -321,7 +321,9 @@ Generated from LIDL (not from `--from-header`). Each module gets **one** ` / LogosMap / LogosList / int64_t / StdLogosResult | +| `lp` | std::string / std::vector / LogosMap / LogosList / int64_t / StdLogosResult, over the Qt-free logos-protocol C ABI | + +(`std` — the same signatures over a `QVariant` / `LogosAPIClient` body — was retired; `--api-style=std` is now an error.) Both styles provide: diff --git a/cpp-generator/legacy/generator_lib.cpp b/cpp-generator/legacy/generator_lib.cpp index 9559fb0..cb656ad 100644 --- a/cpp-generator/legacy/generator_lib.cpp +++ b/cpp-generator/legacy/generator_lib.cpp @@ -101,16 +101,14 @@ QString toQVariantConversion(const QString& type, const QString& argExpr) return argExpr + ".toString()"; } -// ─── Std (pure-C++) type-mapping helpers ───────────────────────────────── +// ─── std (pure-C++) type-mapping table ─────────────────────────────────── // -// File-local — not exposed in generator_lib.h. The single public entry -// point is makeHeader / makeSource taking an `ApiStyle` argument; when -// `apiStyle == Std`, those functions internally route through these -// helpers to pick the std type-mapping table. There's only one wrapper -// class per module — `` — whose signatures depend on apiStyle. -// The std-typed body still goes through the QVariant wire; the Qt↔std -// conversion is inlined at the call site, contained to the generated -// .cpp so callers never include Qt headers. +// File-local — not exposed in generator_lib.h. This is the type table the +// Qt-free surface (ApiStyle::Lp) exposes: the wrapper's signatures are std +// types so a universal / cdylib module's own translation units never name a +// Qt type. Reached through paramTypeFor / returnTypeFor / byRefFor below (the +// non-Qt arm of each) and directly from the Lp backend's lpPushExpr / +// lpFromJsonExpr. static QString mapParamTypeStd(const QString& qtType) { @@ -146,81 +144,6 @@ static QString mapReturnTypeStd(const QString& qtType) return base; } -// Returns a C++ expression that lifts a std-typed parameter into a -// QVariant-side temporary suitable for invokeRemoteMethod. The -// temporaries are rvalues consumed inline at the call site. -static QString stdParamToQVariant(const QString& qtType, const QString& argName) -{ - const QString base = mapParamType(qtType); - if (base == "QString") - return "QString::fromStdString(" + argName + ")"; - if (base == "QStringList") - return "[&]{ QStringList _q; _q.reserve(static_cast(" + argName + - ".size())); for (const auto& _s : " + argName + - ") _q.append(QString::fromStdString(_s)); return _q; }()"; - if (base == "QByteArray") - return "QByteArray(reinterpret_cast(" + argName + - ".data()), static_cast(" + argName + ".size()))"; - if (base == "QJsonArray") - return "QJsonDocument::fromJson(QByteArray::fromStdString(" + argName + - ".dump())).array()"; - if (base == "QVariantList" || base == "QVariantMap" || base == "QVariant") - return "QJsonDocument::fromJson(QByteArray::fromStdString(" + argName + - ".dump())).toVariant()" + (base == "QVariantList" ? ".toList()" - : base == "QVariantMap" ? ".toMap()" - : ""); - if (base == "int") - // The std signature exposes `int64_t`; widen the QVariant - // payload to qlonglong so the wire carries the full 64-bit - // value instead of silently truncating to 32 bits on the way - // through `static_cast`. (Reported by Copilot review on - // PR #61 — the std-typed surface and the wire payload were - // disagreeing for any value outside the int32 range.) - return "static_cast(" + argName + ")"; - return argName; -} - -// Returns a C++ expression that converts a QVariant return value into -// the std-typed return type. `varExpr` is the source QVariant. -static QString qVariantToStdReturn(const QString& qtType, const QString& varExpr) -{ - const QString base = mapReturnType(qtType); - if (base == "void") - return QString(); - if (base == "bool") - return varExpr + ".toBool()"; - if (base == "int") - return "static_cast(" + varExpr + ".toInt())"; - if (base == "qlonglong") - return varExpr + ".toLongLong()"; - if (base == "qulonglong") - return varExpr + ".toULongLong()"; - if (base == "double" || base == "float") - return varExpr + ".toDouble()"; - if (base == "QString") - return varExpr + ".toString().toStdString()"; - if (base == "QStringList") - return "[&]{ std::vector _v; const QStringList _q = " + - varExpr + ".toStringList(); _v.reserve(static_cast(_q.size())); " - "for (const QString& _s : _q) _v.push_back(_s.toStdString()); return _v; }()"; - if (base == "QByteArray") - return "[&]{ const QByteArray _b = " + varExpr + - ".toByteArray(); return std::vector(_b.begin(), _b.end()); }()"; - if (base == "QJsonArray" || base == "QVariantList") - return "LogosList::parse(QJsonDocument(QJsonArray::fromVariantList(" + - varExpr + ".toList())).toJson(QJsonDocument::Compact).toStdString())"; - if (base == "QVariantMap" || base == "QVariant") - return "LogosMap::parse(QJsonDocument(QJsonObject::fromVariantMap(" + - varExpr + ".toMap())).toJson(QJsonDocument::Compact).toStdString())"; - if (base == "LogosResult") - return "[&]{ StdLogosResult _r; const LogosResult _q = " + varExpr + - ".value(); _r.success = _q.success; " - "if (_q.value.isValid()) _r.value = LogosMap::parse(" - "QJsonDocument(QJsonObject::fromVariantMap(_q.value.toMap())).toJson(QJsonDocument::Compact).toStdString()); " - "_r.error = _q.error.toString().toStdString(); return _r; }()"; - return varExpr + ".toString().toStdString()"; -} - // ─── Records ───────────────────────────────────────────────────────────── // // A contract's `type Status { port: uint }` is a REAL C++ struct on the @@ -343,12 +266,9 @@ static QString recordToWireExpr(const RecordSet& rs, const QString& t, ApiStyle if (shape == RecordShape::List) return "[&]{ QVariantList __acc; for (const auto& __e : " + expr + ") __acc.append(" + conv + "(__e)); return __acc; }()"; - // Qt keys are QString, std keys std::string. - if (style == ApiStyle::Qt) - return "[&]{ QVariantMap __acc; for (auto __i = " + expr + ".cbegin(); __i != " + expr - + ".cend(); ++__i) __acc.insert(__i.key(), " + conv + "(__i.value())); return __acc; }()"; - return "[&]{ QVariantMap __acc; for (const auto& __kv : " + expr - + ") __acc.insert(QString::fromStdString(__kv.first), " + conv + "(__kv.second)); return __acc; }()"; + // Map, Qt surface: the source container is a QMap, so keys are QString. + return "[&]{ QVariantMap __acc; for (auto __i = " + expr + ".cbegin(); __i != " + expr + + ".cend(); ++__i) __acc.insert(__i.key(), " + conv + "(__i.value())); return __acc; }()"; } static QString recordFromWireExpr(const RecordSet& rs, const QString& t, ApiStyle style, @@ -372,13 +292,10 @@ static QString recordFromWireExpr(const RecordSet& rs, const QString& t, ApiStyl if (shape == RecordShape::List) return "[&]{ " + cpp + " __acc; for (const QVariant& __e : (" + wire + ").toList()) __acc.push_back(" + conv + "(__e)); return __acc; }()"; - if (style == ApiStyle::Qt) - return "[&]{ " + cpp + " __acc; const QVariantMap __src = (" + wire - + ").toMap(); for (auto __i = __src.cbegin(); __i != __src.cend(); ++__i) " - "__acc.insert(__i.key(), " + conv + "(__i.value())); return __acc; }()"; + // Map, Qt surface: the destination container is a QMap, so keys are QString. return "[&]{ " + cpp + " __acc; const QVariantMap __src = (" + wire + ").toMap(); for (auto __i = __src.cbegin(); __i != __src.cend(); ++__i) " - "__acc[__i.key().toStdString()] = " + conv + "(__i.value()); return __acc; }()"; + "__acc.insert(__i.key(), " + conv + "(__i.value())); return __acc; }()"; } // Param-type predicate: passed by const-ref? @@ -433,13 +350,12 @@ static bool byRefFor(const QString& qtType, const QString& cppType, ApiStyle sty return (style == ApiStyle::Qt) ? isQtRefType(cppType) : isStdRefType(cppType); } -// Typed value -> wire value (QVariant for Qt/Std, nlohmann::json for Lp). +// Typed value -> wire value (QVariant for Qt, nlohmann::json for Lp). static QString toWireFor(const QString& qtType, ApiStyle style, const RecordSet& rs, const QString& expr) { const QString rec = recordToWireExpr(rs, qtType, style, expr); if (!rec.isEmpty()) return rec; if (style == ApiStyle::Lp) return lpPushExpr(qtType, expr); - if (style == ApiStyle::Std) return stdParamToQVariant(qtType, expr); return expr; // Qt: the wrapper's own surface already IS the wire type } @@ -450,7 +366,6 @@ static QString fromWireFor(const QString& qtType, ApiStyle style, const RecordSe const QString rec = recordFromWireExpr(rs, qtType, style, wire, qual); if (!rec.isEmpty()) return rec; if (style == ApiStyle::Lp) return lpFromJsonExpr(qtType, wire); - if (style == ApiStyle::Std) return qVariantToStdReturn(qtType, wire); return toQVariantConversion(mapParamType(qtType), wire); } @@ -505,7 +420,7 @@ static void emitRecordConversions(QTextStream& s, const RecordSet& rs, ApiStyle const QString v = toWireFor(f.type, style, rs, "v." + f.name); const bool isRec = recordShape(rs, f.type, nullptr) != RecordShape::None; s << " __m.insert(QStringLiteral(\"" << f.name << "\"), " - << (isRec || style == ApiStyle::Std ? v : "QVariant::fromValue(" + v + ")") + << (isRec ? v : "QVariant::fromValue(" + v + ")") << ");\n"; } s << " return __m;\n"; @@ -545,43 +460,19 @@ QString makeHeader(const QString& moduleName, const QString& className, const QJ QString h; QTextStream s(&h); s << "#pragma once\n"; - if (apiStyle == ApiStyle::Std) { - // Pure-C++ surface. Qt is still pulled in transitively by - // logos_api.h (LogosAPI is a QObject), but the wrapper's - // signatures are entirely std types so callers never have to - // type a Qt name themselves. - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \"logos_types.h\"\n"; - s << "#include \"logos_json.h\"\n"; - s << "#include \"logos_result.h\"\n"; - s << "#include \"logos_api.h\"\n"; - s << "#include \"logos_api_client.h\"\n"; - s << "#include \"logos_call_error.h\"\n"; - // Needed for the m_eventReplica member when the module declares - // any events. Cheap to include unconditionally — keeps the - // header symmetric with the Qt-style branch. - if (!events.isEmpty()) s << "#include \"logos_object.h\"\n"; - // Record maps are std::map on the std surface. - if (!rs.isEmpty()) s << "#include \n"; - s << "\n"; - } else { - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \"logos_types.h\"\n"; - s << "#include \"logos_api.h\"\n"; - s << "#include \"logos_api_client.h\"\n"; - s << "#include \"logos_call_error.h\"\n"; - s << "#include \"logos_object.h\"\n\n"; - } + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \n"; + s << "#include \"logos_types.h\"\n"; + s << "#include \"logos_api.h\"\n"; + s << "#include \"logos_api_client.h\"\n"; + s << "#include \"logos_call_error.h\"\n"; + s << "#include \"logos_object.h\"\n\n"; s << "class " << className << " {\n"; s << "public:\n"; emitRecordStructs(s, rs, apiStyle); @@ -591,31 +482,28 @@ QString makeHeader(const QString& moduleName, const QString& className, const QJ } else { s << " explicit " << className << "(LogosAPI* api);\n\n"; } - if (apiStyle == ApiStyle::Qt) { - // Event subscription / trigger surface — Qt-typed. - s << " using RawEventCallback = std::function;\n"; - s << " using EventCallback = std::function;\n\n"; - s << " bool on(const QString& eventName, RawEventCallback callback);\n"; - s << " bool on(const QString& eventName, EventCallback callback);\n"; - s << " void setEventSource(LogosObject* source);\n"; - s << " LogosObject* eventSource() const;\n"; - s << " void trigger(const QString& eventName);\n"; - s << " void trigger(const QString& eventName, const QVariantList& data);\n"; - s << " template\n"; - s << " void trigger(const QString& eventName, Args&&... args) {\n"; - s << " trigger(eventName, packVariantList(std::forward(args)...));\n"; - s << " }\n"; - s << " void trigger(const QString& eventName, LogosObject* source, const QVariantList& data);\n"; - s << " template\n"; - s << " void trigger(const QString& eventName, LogosObject* source, Args&&... args) {\n"; - s << " trigger(eventName, source, packVariantList(std::forward(args)...));\n"; - s << " }\n\n"; - } + // Event subscription / trigger surface — Qt-typed. + s << " using RawEventCallback = std::function;\n"; + s << " using EventCallback = std::function;\n\n"; + s << " bool on(const QString& eventName, RawEventCallback callback);\n"; + s << " bool on(const QString& eventName, EventCallback callback);\n"; + s << " void setEventSource(LogosObject* source);\n"; + s << " LogosObject* eventSource() const;\n"; + s << " void trigger(const QString& eventName);\n"; + s << " void trigger(const QString& eventName, const QVariantList& data);\n"; + s << " template\n"; + s << " void trigger(const QString& eventName, Args&&... args) {\n"; + s << " trigger(eventName, packVariantList(std::forward(args)...));\n"; + s << " }\n"; + s << " void trigger(const QString& eventName, LogosObject* source, const QVariantList& data);\n"; + s << " template\n"; + s << " void trigger(const QString& eventName, LogosObject* source, Args&&... args) {\n"; + s << " trigger(eventName, source, packVariantList(std::forward(args)...));\n"; + s << " }\n\n"; // Typed event subscribers — generated from the `.lidl` sidecar shipped // with the dep's pre-built headers (via --events-from). One typed // adapter per declared event, callback-arg types follow apiStyle. - // The generic `on(name, cb)` channel above stays available; for - // std-style consumers it's not exposed but the typed accessors are. + // The generic `on(name, cb)` channel above stays available alongside them. for (const QJsonValue& ev : events) { const QJsonObject eo = ev.toObject(); const QString evName = eo.value("name").toString(); @@ -690,34 +578,23 @@ QString makeHeader(const QString& moduleName, const QString& className, const QJ s << asyncCallbackType << " callback, Timeout timeout = Timeout());\n"; } s << "\nprivate:\n"; - // ensureReplica() is needed whenever the wrapper subscribes to - // events — in Qt mode that's always (the generic `on(...)` channel - // is exposed); in std mode it's gated on at least one declared - // event in the LIDL sidecar. - if (apiStyle == ApiStyle::Qt || !events.isEmpty()) { - s << " LogosObject* ensureReplica();\n"; - } - if (apiStyle == ApiStyle::Qt) { - s << " template\n"; - s << " static QVariantList packVariantList(Args&&... args) {\n"; - s << " QVariantList list;\n"; - s << " list.reserve(sizeof...(Args));\n"; - s << " using Expander = int[];\n"; - s << " (void)Expander{0, (list.append(QVariant::fromValue(std::forward(args))), 0)...};\n"; - s << " return list;\n"; - s << " }\n"; - } + // ensureReplica() is needed whenever the wrapper subscribes to events, + // which on the Qt surface is always: the generic `on(...)` channel is + // exposed even when the contract declares no typed events. + s << " LogosObject* ensureReplica();\n"; + s << " template\n"; + s << " static QVariantList packVariantList(Args&&... args) {\n"; + s << " QVariantList list;\n"; + s << " list.reserve(sizeof...(Args));\n"; + s << " using Expander = int[];\n"; + s << " (void)Expander{0, (list.append(QVariant::fromValue(std::forward(args))), 0)...};\n"; + s << " return list;\n"; + s << " }\n"; s << " LogosAPI* m_api;\n"; s << " LogosAPIClient* m_client;\n"; s << " QString m_moduleName;\n"; - if (apiStyle == ApiStyle::Qt) { - s << " LogosObject* m_eventReplica = nullptr;\n"; - s << " LogosObject* m_eventSource = nullptr;\n"; - } else if (!events.isEmpty()) { - // std-style consumer: only the receive-side replica is needed - // (no `trigger(...)` API on the std wrapper, so no eventSource). - s << " LogosObject* m_eventReplica = nullptr;\n"; - } + s << " LogosObject* m_eventReplica = nullptr;\n"; + s << " LogosObject* m_eventSource = nullptr;\n"; s << "};\n"; return h; } @@ -731,24 +608,8 @@ QString makeSource(const QString& moduleName, const QString& className, const QS QTextStream s(&c); s << "#include \"" << headerBaseName << "\"\n\n"; s << "#include \n"; - if (apiStyle == ApiStyle::Std) { - // Conversion bridges between std types and QVariant — confined - // to this .cpp so the caller's translation unit doesn't need - // any Qt headers itself. - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - s << "#include \n"; - // logos_object.h is the type of LogosObject* used by typed event - // accessors when the module declares events. Always include in - // std mode when events are present. - if (!events.isEmpty()) s << "#include \"logos_object.h\"\n"; - } - if (apiStyle == ApiStyle::Qt && !rs.isEmpty()) { - // Record conversions build QVariantMaps regardless of api style. + if (!rs.isEmpty()) { + // Record conversions build QVariantMaps. s << "#include \n"; } s << "\n"; @@ -766,79 +627,61 @@ QString makeSource(const QString& moduleName, const QString& className, const QS s << className << "::" << className << "(LogosAPI* api) : m_api(api), m_client(api->getClient(\"" << moduleName << "\")), m_moduleName(QStringLiteral(\"" << moduleName << "\")) {}\n\n"; } - // ensureReplica() — generated for std mode too when events are - // declared. The body is identical to the Qt version; pulled up - // here so both branches share it. - if (apiStyle == ApiStyle::Std && !events.isEmpty()) { - s << "LogosObject* " << className << "::ensureReplica() {\n"; - s << " if (!m_eventReplica) {\n"; - s << " LogosObject* replica = m_client->requestObject(m_moduleName);\n"; - s << " if (!replica) {\n"; - s << " qWarning() << \"" << className << ": failed to acquire remote object for events on\" << m_moduleName;\n"; - s << " return nullptr;\n"; - s << " }\n"; - s << " m_eventReplica = replica;\n"; - s << " }\n"; - s << " return m_eventReplica;\n"; - s << "}\n\n"; - } - if (apiStyle == ApiStyle::Qt) { - s << "LogosObject* " << className << "::ensureReplica() {\n"; - s << " if (!m_eventReplica) {\n"; - s << " LogosObject* replica = m_client->requestObject(m_moduleName);\n"; - s << " if (!replica) {\n"; - s << " qWarning() << \"" << className << ": failed to acquire remote object for events on\" << m_moduleName;\n"; - s << " return nullptr;\n"; - s << " }\n"; - s << " m_eventReplica = replica;\n"; - s << " }\n"; - s << " return m_eventReplica;\n"; - s << "}\n\n"; - s << "bool " << className << "::on(const QString& eventName, RawEventCallback callback) {\n"; - s << " if (!callback) {\n"; - s << " qWarning() << \"" << className << ": ignoring empty event callback for\" << eventName;\n"; - s << " return false;\n"; - s << " }\n"; - s << " LogosObject* origin = ensureReplica();\n"; - s << " if (!origin) {\n"; - s << " return false;\n"; - s << " }\n"; - s << " m_client->onEvent(origin, eventName, callback);\n"; - s << " return true;\n"; - s << "}\n\n"; - s << "bool " << className << "::on(const QString& eventName, EventCallback callback) {\n"; - s << " if (!callback) {\n"; - s << " qWarning() << \"" << className << ": ignoring empty event callback for\" << eventName;\n"; - s << " return false;\n"; - s << " }\n"; - s << " return on(eventName, [callback](const QString&, const QVariantList& data) {\n"; - s << " callback(data);\n"; - s << " });\n"; - s << "}\n\n"; - s << "void " << className << "::setEventSource(LogosObject* source) {\n"; - s << " m_eventSource = source;\n"; - s << "}\n\n"; - s << "LogosObject* " << className << "::eventSource() const {\n"; - s << " return m_eventSource;\n"; - s << "}\n\n"; - s << "void " << className << "::trigger(const QString& eventName) {\n"; - s << " trigger(eventName, QVariantList{});\n"; - s << "}\n\n"; - s << "void " << className << "::trigger(const QString& eventName, const QVariantList& data) {\n"; - s << " if (!m_eventSource) {\n"; - s << " qWarning() << \"" << className << ": no event source set for trigger\" << eventName;\n"; - s << " return;\n"; - s << " }\n"; - s << " m_client->onEventResponse(m_eventSource, eventName, data);\n"; - s << "}\n\n"; - s << "void " << className << "::trigger(const QString& eventName, LogosObject* source, const QVariantList& data) {\n"; - s << " if (!source) {\n"; - s << " qWarning() << \"" << className << ": cannot trigger\" << eventName << \"with null source\";\n"; - s << " return;\n"; - s << " }\n"; - s << " m_client->onEventResponse(source, eventName, data);\n"; - s << "}\n\n"; - } + s << "LogosObject* " << className << "::ensureReplica() {\n"; + s << " if (!m_eventReplica) {\n"; + s << " LogosObject* replica = m_client->requestObject(m_moduleName);\n"; + s << " if (!replica) {\n"; + s << " qWarning() << \"" << className << ": failed to acquire remote object for events on\" << m_moduleName;\n"; + s << " return nullptr;\n"; + s << " }\n"; + s << " m_eventReplica = replica;\n"; + s << " }\n"; + s << " return m_eventReplica;\n"; + s << "}\n\n"; + s << "bool " << className << "::on(const QString& eventName, RawEventCallback callback) {\n"; + s << " if (!callback) {\n"; + s << " qWarning() << \"" << className << ": ignoring empty event callback for\" << eventName;\n"; + s << " return false;\n"; + s << " }\n"; + s << " LogosObject* origin = ensureReplica();\n"; + s << " if (!origin) {\n"; + s << " return false;\n"; + s << " }\n"; + s << " m_client->onEvent(origin, eventName, callback);\n"; + s << " return true;\n"; + s << "}\n\n"; + s << "bool " << className << "::on(const QString& eventName, EventCallback callback) {\n"; + s << " if (!callback) {\n"; + s << " qWarning() << \"" << className << ": ignoring empty event callback for\" << eventName;\n"; + s << " return false;\n"; + s << " }\n"; + s << " return on(eventName, [callback](const QString&, const QVariantList& data) {\n"; + s << " callback(data);\n"; + s << " });\n"; + s << "}\n\n"; + s << "void " << className << "::setEventSource(LogosObject* source) {\n"; + s << " m_eventSource = source;\n"; + s << "}\n\n"; + s << "LogosObject* " << className << "::eventSource() const {\n"; + s << " return m_eventSource;\n"; + s << "}\n\n"; + s << "void " << className << "::trigger(const QString& eventName) {\n"; + s << " trigger(eventName, QVariantList{});\n"; + s << "}\n\n"; + s << "void " << className << "::trigger(const QString& eventName, const QVariantList& data) {\n"; + s << " if (!m_eventSource) {\n"; + s << " qWarning() << \"" << className << ": no event source set for trigger\" << eventName;\n"; + s << " return;\n"; + s << " }\n"; + s << " m_client->onEventResponse(m_eventSource, eventName, data);\n"; + s << "}\n\n"; + s << "void " << className << "::trigger(const QString& eventName, LogosObject* source, const QVariantList& data) {\n"; + s << " if (!source) {\n"; + s << " qWarning() << \"" << className << ": cannot trigger\" << eventName << \"with null source\";\n"; + s << " return;\n"; + s << " }\n"; + s << " m_client->onEventResponse(source, eventName, data);\n"; + s << "}\n\n"; // Typed event adapters — one per declared event. The callback type // uses the apiStyle's type surface; the body unmarshals from the @@ -911,9 +754,8 @@ QString makeSource(const QString& moduleName, const QString& className, const QS const QString retQual = returnTypeFor(qtRet, apiStyle, rs, className + "::"); QJsonArray params = o.value("parameters").toArray(); - // Helper closures kept inline so the two branches don't get - // pulled apart visually — the per-arg / per-return shape is - // the only thing that varies between Qt and Std modes. + // Helper closures kept inline so the signature and the call that + // consumes it stay next to each other. auto emitParam = [&](const QJsonObject& p, bool& byRefOut) { QString qtPt = p.value("type").toString(); QString pt = paramTypeFor(qtPt, apiStyle, rs); @@ -970,8 +812,6 @@ QString makeSource(const QString& moduleName, const QString& className, const QS // nothing } else if (retIsRecord) { s << " return " << fromWireFor(qtRet, apiStyle, rs, "_result") << ";\n"; - } else if (apiStyle == ApiStyle::Std) { - s << " return " << qVariantToStdReturn(qtRet, "_result") << ";\n"; } else if (ret == "bool") { s << " return _result.toBool();\n"; } else if (ret == "qlonglong") { @@ -1036,22 +876,6 @@ QString makeSource(const QString& moduleName, const QString& className, const QS // A record decodes field by field; an invalid QVariant yields a // default-constructed struct, matching the scalar paths. s << " callback(" << fromWireFor(qtRet, apiStyle, rs, "v", className + "::") << ");\n"; - } else if (apiStyle == ApiStyle::Std) { - // Default-construct on dispatch failure, matching the - // existing Qt code path which falls back to a zero / empty - // value when the QVariant is invalid. - QString defaultVal; - if (ret == "bool") defaultVal = "false"; - else if (ret == "int64_t") defaultVal = "0"; - else if (ret == "double") defaultVal = "0.0"; - else if (ret == "std::string") defaultVal = "std::string()"; - else if (ret.startsWith("std::vector")) defaultVal = ret + "()"; - else if (ret == "LogosMap") defaultVal = "LogosMap::object()"; - else if (ret == "LogosList") defaultVal = "LogosList::array()"; - else if (ret == "StdLogosResult") defaultVal = "StdLogosResult{}"; - else defaultVal = ret + "{}"; - s << " if (!v.isValid()) { callback(" << defaultVal << "); return; }\n"; - s << " callback(" << qVariantToStdReturn(qtRet, "v") << ");\n"; } else { QString defaultVal; if (ret == "bool") defaultVal = "false"; @@ -1187,12 +1011,15 @@ QVector parseProviderHeader(const QString& headerPath, QTextStream // ─── ApiStyle::Lp (Qt-free) wrapper emission ───────────────────────────── // -// Same std-typed surface as ApiStyle::Std, but the generated body calls the -// logos-protocol C ABI through logos::LpClient instead of LogosAPIClient, so -// the wrapper's translation unit pulls in no Qt. Used for the cdylib outbound -// path (a Qt-free module calling its dependencies / subscribing to their -// events). The class still holds a single target; Static bakes it, Bound takes -// it at construction (interface dependencies). +// A std-typed surface (the mapParamTypeStd / mapReturnTypeStd table above) +// whose generated body calls the logos-protocol C ABI through logos::LpClient +// instead of LogosAPIClient, so the wrapper's translation unit pulls in no Qt. +// This is the only remaining std-typed flavour; the retired ApiStyle::Std +// exposed the same signatures over a QVariant + LogosAPIClient body. +// +// Used for the cdylib outbound path (a Qt-free module calling its dependencies +// / subscribing to their events). The class still holds a single target; +// Static bakes it, Bound takes it at construction (interface dependencies). // std value -> nlohmann::json push expression. nlohmann handles // string/int64/double/bool/vector/json (LogosMap/LogosList) directly; diff --git a/cpp-generator/legacy/generator_lib.h b/cpp-generator/legacy/generator_lib.h index 0704b3f..69e26e8 100644 --- a/cpp-generator/legacy/generator_lib.h +++ b/cpp-generator/legacy/generator_lib.h @@ -17,18 +17,21 @@ struct ParsedMethod { // Which type surface to expose on the generated per-module wrapper. // Each module's build picks ONE — there's no composite output. Default // is Qt for backward compatibility; `interface: "universal"` modules -// flip to Std via the -DLOGOS_API_STYLE=std CMake flag the module -// builder threads through. +// flip to Lp via the -DLOGOS_API_STYLE=lp CMake flag the module builder +// threads through. // Qt — legacy Qt-typed surface (QString/QVariant…), body via LogosAPIClient. -// Std — std-typed surface, but the body still bridges through QVariant + -// LogosAPIClient (so the wrapper .cpp links qt-sdk). // Lp — std-typed surface AND a Qt-free body: the wrapper calls the // logos-protocol C ABI (lp_*) directly via logos::LpClient, so the // module's translation units never include Qt or link qt-sdk. This is // the path that lets a cdylib module do outbound typed calls/event // subscriptions while staying Qt-free (Qt confined to the QRO transport // inside logos-protocol + the generated plugin glue). -enum class ApiStyle { Qt, Std, Lp }; +// +// A third flavour, Std, used to sit between the two: the std-typed surface +// with a body that still bridged through QVariant + LogosAPIClient. Nothing +// selected it any more (universal modules go straight to Lp), so it was +// retired; `--api-style=std` is now a hard error rather than a silent alias. +enum class ApiStyle { Qt, Lp }; // Whether the generated wrapper targets ONE fixed module (the historical // behaviour) or binds to a module name chosen at runtime. @@ -57,14 +60,12 @@ QString toProviderArgDecode(const QString& type, const QString& argExpr, const QString& path); // makeHeader / makeSource emit the single `` wrapper for a -// module. When `apiStyle == Std`, parameter / return types come from -// the std-typed mapping table (std::string / std::vector -// / LogosMap / LogosList / int64_t / StdLogosResult) and the .cpp -// body wraps the QVariant wire with inline Qt↔std conversions — -// callers never include Qt headers. When `apiStyle == Qt`, the output -// matches the legacy Qt-typed surface (QString / QStringList / -// QVariantList / QVariantMap / int / LogosResult). The class name is -// always `` either way; the two styles are mutually exclusive. +// module. When `apiStyle == Qt`, the output is the legacy Qt-typed +// surface (QString / QStringList / QVariantList / QVariantMap / int / +// LogosResult) with a body that calls LogosAPIClient. When +// `apiStyle == Lp`, they delegate to makeHeaderLp / makeSourceLp below, +// which emit the std-typed, Qt-free surface. The class name is always +// `` either way; the two styles are mutually exclusive. // // `events` carries typed event prototypes loaded from a `.lidl` // sidecar via --events-from. Each entry is @@ -92,8 +93,9 @@ QString toProviderArgDecode(const QString& type, const QString& argExpr, QString makeHeader(const QString& moduleName, const QString& className, const QJsonArray& methods, ApiStyle apiStyle = ApiStyle::Qt, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); QString makeSource(const QString& moduleName, const QString& className, const QString& headerBaseName, const QJsonArray& methods, ApiStyle apiStyle = ApiStyle::Qt, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); -// Qt-free (ApiStyle::Lp) wrapper emission. Same std-typed surface as the Std -// flavor, but the generated body calls the logos-protocol C ABI through +// Qt-free (ApiStyle::Lp) wrapper emission. A std-typed surface +// (std::string / std::vector / LogosMap / LogosList / int64_t / +// StdLogosResult) whose generated body calls the logos-protocol C ABI through // logos::LpClient instead of LogosAPIClient — no Qt in the wrapper's TU. // makeHeader/makeSource dispatch here when apiStyle == ApiStyle::Lp. QString makeHeaderLp(const QString& moduleName, const QString& className, const QJsonArray& methods, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); diff --git a/cpp-generator/legacy/main.cpp b/cpp-generator/legacy/main.cpp index 1e0ec16..5879864 100644 --- a/cpp-generator/legacy/main.cpp +++ b/cpp-generator/legacy/main.cpp @@ -389,7 +389,7 @@ static bool writeUmbrellaHeader(const QString& genDirPath, QTextStream& err) { // Generate logos_sdk.h: include every per-module wrapper header in // the gen dir and aggregate them into a flat `LogosModules` struct. - // The wrappers may be Qt-typed or Std-typed depending on the + // The wrappers may be Qt-typed or std-typed (lp) depending on the // --api-style picked for this build; the umbrella shape doesn't // change because either flavor produces the same accessor name // (``) on the same class name (``). @@ -880,8 +880,9 @@ static int generateFromPlugin(const QString& pluginInputPath, const QString& out // Single per-module wrapper file pair. apiStyle decides the // signature shape: Qt-typed for legacy / handcrafted callers - // (default), std-typed when the consuming module's build passed - // --api-style=std (typically because it's `interface: "universal"`). + // (default), std-typed and Qt-free when the consuming module's build + // passed --api-style=lp (typically because it's `interface: + // "universal"` or `"cdylib"`). // Both produce the same filename and class name, so the umbrella // doesn't need to know which style was picked. `events` (loaded // from a sibling `.lidl` sidecar via --events-from) adds typed @@ -955,14 +956,19 @@ int legacy_main(int argc, char* argv[]) // Parse --general-only option bool generalOnly = args.contains("--general-only"); - // Parse --api-style option (qt | std). Picks which type surface + // Parse --api-style option (qt | lp). Picks which type surface // the generated `` wrapper exposes. Default is qt for // backward compatibility — every existing module that doesn't // declare `interface: "universal"` in its metadata.json keeps - // its Qt-typed LogosModules surface. Universal modules get - // -DLOGOS_API_STYLE=std threaded through by mkLogosModule.nix / - // LogosModule.cmake, which becomes `--api-style=std` here. - // Both forms accepted: `--api-style std` and `--api-style=std`. + // its Qt-typed LogosModules surface. Universal / cdylib modules get + // -DLOGOS_API_STYLE=lp threaded through by mkLogosModule.nix / + // LogosModule.cmake, which becomes `--api-style=lp` here. + // Both forms accepted: `--api-style lp` and `--api-style=lp`. + // + // `std` was a third surface (std types over a QVariant/LogosAPIClient + // body). It is retired, and rejected LOUDLY rather than aliased to qt: + // a stale caller that still passes it wants std signatures, and silently + // handing it the Qt surface would only fail later, further from the cause. ApiStyle apiStyle = ApiStyle::Qt; { QString apiVal; @@ -977,11 +983,17 @@ int legacy_main(int argc, char* argv[]) break; } } - if (apiVal == "std") apiStyle = ApiStyle::Std; + if (apiVal == "std") { + err << "--api-style=std was retired: the Std surface (std types over a " + << "QVariant/LogosAPIClient body) no longer exists.\n" + << "Use 'lp' for the Qt-free std-typed surface, or 'qt' for the " + << "Qt-typed one.\n"; + return 1; + } else if (apiVal == "lp") apiStyle = ApiStyle::Lp; else if (!apiVal.isEmpty() && apiVal != "qt") { err << "Unknown --api-style value: " << apiVal - << " (expected 'qt', 'std', or 'lp')\n"; + << " (expected 'qt' or 'lp')\n"; return 1; } } diff --git a/tests/generator/test_records.cpp b/tests/generator/test_records.cpp index 09c869a..155c9b7 100644 --- a/tests/generator/test_records.cpp +++ b/tests/generator/test_records.cpp @@ -2,7 +2,7 @@ // C++ module actually gets for its dependencies (`--dep =`). // // A contract's `type Status { ... }` used to reach every C++ consumer as an -// untyped bag: QVariant on the Qt surface, LogosMap on the std/lp one. The +// untyped bag: QVariant on the Qt surface, LogosMap on the lp one. The // caller then had to know the field names AND, for a `bstr` field, that the // value arrives as the canonical `{"_bytes": "..."}` envelope it must unwrap // itself — while Rust and the client-stub backend hand back a real struct. @@ -97,11 +97,11 @@ TEST(Records, QtWrapperExposesTheStruct) EXPECT_FALSE(h.contains("describeStatus(QVariant")); } -// The std / lp surfaces spell the same records in std types — a universal +// The lp surface spells the same records in std types — a universal // (Qt-free) module never sees a Qt name. -TEST(Records, StdAndLpWrappersUseStdFieldTypes) +TEST(Records, LpWrapperUsesStdFieldTypes) { - for (ApiStyle style : {ApiStyle::Std, ApiStyle::Lp}) { + for (ApiStyle style : {ApiStyle::Lp}) { const QString h = makeHeader("info_module", "InfoModule", statusMethods(), style, {}, BindMode::Static, statusRecords()); EXPECT_TRUE(h.contains(" uint64_t port{};")) << h.toStdString(); @@ -113,7 +113,7 @@ TEST(Records, StdAndLpWrappersUseStdFieldTypes) EXPECT_FALSE(h.contains("LogosMap getStatus(")); } - // std::map needs its header on the std/lp surfaces. + // std::map needs its header on the lp surface. const QString lp = makeHeader("info_module", "InfoModule", statusMethods(), ApiStyle::Lp, {}, BindMode::Static, statusRecords()); EXPECT_TRUE(lp.contains("#include ")); @@ -136,7 +136,7 @@ TEST(Records, BytesFieldsUseTheCanonicalEncoding) EXPECT_TRUE(qt.contains("__out.blob = __m.value(QStringLiteral(\"blob\")).toByteArray();")); } -// The conversions are file-local statics in the .cpp: a std/lp consumer's own +// The conversions are file-local statics in the .cpp: an lp consumer's own // translation units must not need the wire type to include the header. TEST(Records, ConversionsStayOutOfTheHeader) { @@ -172,11 +172,11 @@ TEST(Records, ReturnTypesAreQualifiedInTheDefinition) // from its own uninitialized local — it compiled, with only a warning. TEST(Records, ContainerLambdasDoNotShadowTheDecoderLocals) { - for (ApiStyle style : {ApiStyle::Qt, ApiStyle::Std, ApiStyle::Lp}) { + for (ApiStyle style : {ApiStyle::Qt, ApiStyle::Lp}) { const QString c = makeSource("info_module", "InfoModule", "info_module_api.h", statusMethods(), style, {}, BindMode::Static, statusRecords()); - // The decoder's own map is `__m` (Qt/Std); a nested lambda must not + // The decoder's own map is `__m` (Qt); a nested lambda must not // declare another one. EXPECT_FALSE(c.contains("const QVariantMap __m = (__m.value")) << c.toStdString(); EXPECT_FALSE(c.contains("const nlohmann::json& __j = w.at")) << c.toStdString(); @@ -188,7 +188,7 @@ TEST(Records, ContainerLambdasDoNotShadowTheDecoderLocals) TEST(Records, EmptyRecordSetChangesNothing) { const QJsonArray methods{method("ping", "QString", QJsonArray{param("msg", "QString")})}; - for (ApiStyle style : {ApiStyle::Qt, ApiStyle::Std, ApiStyle::Lp}) { + for (ApiStyle style : {ApiStyle::Qt, ApiStyle::Lp}) { EXPECT_EQ(makeHeader("m", "M", methods, style, {}, BindMode::Static, {}), makeHeader("m", "M", methods, style, {}, BindMode::Static)); EXPECT_EQ(makeSource("m", "M", "m_api.h", methods, style, {}, BindMode::Static, {}),