mirror of
https://github.com/logos-co/logos-test-modules.git
synced 2026-08-31 04:01:16 +00:00
One contract had two providers answering different SHAPES. test_fullapi_ext_rust.lidl declared `echoOptional(v: ?tstr) -> result`; test_fullapi_ext_cpp is header-first and kept deriving `-> ?tstr` from `std::optional<std::string> echoOptional(...)`. Carried as known-ext.json's `ext-optional-return-changed-on-one-provider`, and visible on a second surface as `ext-optional-return-shape-through-the-qt-proxy`. THE WORKAROUND OUTLIVED ITS CAUSE. `-> result` was chosen because `logos-qt-generator --backend consumer` REFUSED `-> ?T` -- null was also how a failed call reported itself on that path, so an empty ?T and a failure were one wire value. That gate is retired: `lidlTypeToQt` maps `?T` to std::optional<T>, so the empty answer is std::nullopt, an inhabitant of its own, and failure travels on logos::CallError, decided by the C ABI return code and never by the value's null-ness. So `-> ?tstr` is emittable today, it is what the C++ provider already derives, and it is what the case table already expects. Reverting the Rust side is what makes the two agree; the alternative (moving C++ to `-> result`) would have meant changing the expectations to match a workaround for a constraint that no longer exists. Changed together, because a proxy that forwards a shape must declare the same one: the Rust LIDL and its impl (`Option<String>` in and out, no success flag standing in for presence), the qtproxy's own interfaces/full_api_ext.lidl, and the qtproxy impl's echoOptional -- which now forwards through sOptStr rather than sResult, and renders with rOpt rather than rResult in the exercise-all and async blocks. Both registry entries are retired. The proxy one had a SECOND, independent half -- a Qt wrapper that could not decode a reply returned a default-constructed LogosResult, and that default is byte-for-byte a provider refusal -- which is fixed in logos-qt-sdk#44 and logos-cpp-sdk#150 and stands whichever shape the contract had chosen. Recorded in the `fixed` entry, because retiring it here without naming that half would credit the shape change with more than it did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
63 lines
2.4 KiB
Plaintext
63 lines
2.4 KiB
Plaintext
module full_api_ext {
|
|
version "1.0.0"
|
|
description "The composite tail of the conformance matrix — records, bytes at depth, typed maps, nested composites and optionality — as a BINDABLE interface. Bound at runtime to test_fullapi_ext_cpp or test_fullapi_ext_rust."
|
|
|
|
; The three records, spelled exactly as both providers declare them. The Qt
|
|
; consumer emits each as a nested struct on the wrapper class
|
|
; (FullApiExt::Blob, …), so they do NOT collide with the std-typed structs
|
|
; the proxy's own provider surface declares at global scope.
|
|
type Blob {
|
|
id: tstr
|
|
n: uint
|
|
payload: bstr
|
|
}
|
|
|
|
type Wrapper {
|
|
inner: Blob
|
|
tags: [tstr]
|
|
blobs: [Blob]
|
|
}
|
|
|
|
; Both optionality spellings are load-bearing here for the same reason the
|
|
; providers' contracts give: `? maybe: tstr` (the field flag) and `?tstr` (the
|
|
; type kind, in echoOptional) are bound to the same meaning and must emit the
|
|
; same code. On the Qt consumer surface that meaning is std::optional<T> —
|
|
; std::optional<QString>, std::optional<qulonglong>, std::optional<QByteArray>
|
|
; — which is the mapping this interface exists to exercise through a proxy hop.
|
|
type Opt {
|
|
required: tstr
|
|
? maybe: tstr
|
|
? count: uint
|
|
? blob: bstr
|
|
}
|
|
|
|
method whoAmI() -> tstr
|
|
|
|
method echoBlob(v: Blob) -> Blob
|
|
method echoWrapper(v: Wrapper) -> Wrapper
|
|
method echoBlobList(v: [Blob]) -> [Blob]
|
|
method echoBlobMap(v: {tstr: Blob}) -> {tstr: Blob}
|
|
|
|
method echoBytesList(v: [bstr]) -> [bstr]
|
|
method echoBytesMap(v: {tstr: bstr}) -> {tstr: bstr}
|
|
method echoIntMap(v: {tstr: int}) -> {tstr: int}
|
|
method echoStringMap(v: {tstr: tstr}) -> {tstr: tstr}
|
|
method echoNestedInts(v: [[int]]) -> [[int]]
|
|
method echoMapOfBytesLists(v: {tstr: [bstr]}) -> {tstr: [bstr]}
|
|
|
|
; `-> result`, following test_fullapi_ext_rust.lidl — the file the matrix
|
|
; driver is handed as --contract and the one the ext case table computes its
|
|
; coverage from (Optional/scalar/present declares the (result, method_return)
|
|
; cell explicitly). test_fullapi_ext_cpp is header-first and still derives
|
|
; `-> ?tstr` from std::optional<std::string>; that disagreement is the
|
|
; already-registered `ext-optional-return-changed-on-one-provider`, and this
|
|
; interface must pick ONE shape rather than invent a third.
|
|
method echoOpt(v: Opt) -> Opt
|
|
method echoOptList(v: [Opt]) -> [Opt]
|
|
method echoOptional(v: ?tstr) -> ?tstr
|
|
|
|
method fireBlobEvent(v: Blob) -> bool
|
|
|
|
event blobEvent(v: Blob)
|
|
}
|